2015-03-19 12:18:19 +03:00
/*
This file is part of Telegram Desktop ,
the official desktop version of Telegram messaging app , see https : //telegram.org
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 16:16:42 +03: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 .
2015-03-19 12:18:19 +03:00
Full license : https : //github.com/telegramdesktop/tdesktop/blob/master/LICENSE
2017-01-11 22:31:31 +04:00
Copyright ( c ) 2014 - 2017 John Preston , https : //desktop.telegram.org
2015-03-19 12:18:19 +03:00
*/
2016-04-21 20:57:29 +03:00
# include "apiwrap.h"
2015-03-19 12:18:19 +03:00
2016-06-09 17:31:10 +03:00
# include "data/data_drafts.h"
2017-09-26 14:49:16 +03:00
# include "data/data_photo.h"
# include "data/data_web_page.h"
2017-11-20 23:54:05 +04:00
# include "core/tl_help.h"
2017-11-21 15:59:18 +04:00
# include "base/overload.h"
2016-05-25 15:09:05 +03:00
# include "observer_peer.h"
2017-04-13 11:27:10 +03:00
# include "lang/lang_keys.h"
2015-03-19 12:18:19 +03:00
# include "application.h"
2016-04-13 00:31:28 +03:00
# include "mainwindow.h"
2017-04-29 23:06:32 +03:00
# include "messenger.h"
2015-03-19 12:18:19 +03:00
# include "mainwidget.h"
2017-06-29 13:27:09 +03:00
# include "history/history_widget.h"
2017-03-04 13:23:56 +03:00
# include "storage/localstorage.h"
2017-02-23 12:32:28 +03:00
# include "auth_session.h"
2017-04-06 17:38:10 +03:00
# include "boxes/confirm_box.h"
2017-02-03 23:07:26 +03:00
# include "window/themes/window_theme.h"
2017-03-04 22:36:59 +03:00
# include "window/notifications_manager.h"
2017-04-08 16:27:53 +03:00
# include "chat_helpers/message_field.h"
2017-08-02 22:57:49 +02:00
# include "chat_helpers/stickers.h"
2017-08-18 22:14:31 +03:00
# include "storage/storage_facade.h"
# include "storage/storage_shared_media.h"
2017-08-29 22:52:52 +03:00
# include "storage/storage_user_photos.h"
2017-11-06 11:31:18 +04:00
# include "data/data_sparse_ids.h"
# include "data/data_search_controller.h"
2015-03-19 12:18:19 +03:00
2017-04-06 19:49:42 +03:00
namespace {
constexpr auto kReloadChannelMembersTimeout = 1000 ; // 1 second wait before reload members in channel after adding
2017-04-07 15:10:10 +03:00
constexpr auto kSaveCloudDraftTimeout = 1000 ; // save draft to the cloud with 1 sec extra delay
2017-04-11 18:44:11 +03:00
constexpr auto kSaveDraftBeforeQuitTimeout = 1500 ; // give the app 1.5 secs to save drafts to cloud when quitting
2017-04-06 22:02:40 +03:00
constexpr auto kSmallDelayMs = 5 ;
2017-08-11 09:16:07 +02:00
constexpr auto kUnreadMentionsPreloadIfLess = 5 ;
constexpr auto kUnreadMentionsFirstRequestLimit = 10 ;
constexpr auto kUnreadMentionsNextRequestLimit = 100 ;
2017-08-29 22:52:52 +03:00
constexpr auto kSharedMediaLimit = 100 ;
2017-11-05 21:07:27 +04:00
constexpr auto kReadFeaturedSetsTimeout = TimeMs ( 1000 ) ;
2017-04-06 19:49:42 +03:00
} // namespace
2017-08-17 11:31:24 +03:00
ApiWrap : : ApiWrap ( not_null < AuthSession * > session )
2017-06-05 16:33:45 +03:00
: _session ( session )
, _messageDataResolveDelayed ( [ this ] { resolveMessageDatas ( ) ; } )
2017-04-07 15:10:10 +03:00
, _webPagesTimer ( [ this ] { resolveWebPages ( ) ; } )
2017-11-05 21:07:27 +04:00
, _draftsSaveTimer ( [ this ] { saveDraftsToCloud ( ) ; } )
, _featuredSetsReadTimer ( [ this ] { readFeaturedSets ( ) ; } ) {
2017-06-05 16:33:45 +03:00
}
void ApiWrap : : start ( ) {
2016-11-04 22:50:35 +03:00
Window : : Theme : : Background ( ) - > start ( ) ;
2017-06-30 13:32:10 +03:00
requestAppChangelogs ( ) ;
}
void ApiWrap : : requestAppChangelogs ( ) {
auto oldAppVersion = Local : : oldMapVersion ( ) ;
if ( oldAppVersion > 0 & & oldAppVersion < AppVersion ) {
_changelogSubscription = subscribe ( _session - > data ( ) . moreChatsLoaded ( ) , [ this , oldAppVersion ] {
auto oldVersionString = qsl ( " %1.%2.%3 " ) . arg ( oldAppVersion / 1000000 ) . arg ( ( oldAppVersion % 1000000 ) / 1000 ) . arg ( oldAppVersion % 1000 ) ;
request ( MTPhelp_GetAppChangelog ( MTP_string ( oldVersionString ) ) ) . done ( [ this , oldAppVersion ] ( const MTPUpdates & result ) {
2017-06-05 16:33:45 +03:00
applyUpdates ( result ) ;
2017-06-30 09:23:31 +03:00
2017-06-30 13:32:10 +03:00
auto resultEmpty = true ;
switch ( result . type ( ) ) {
case mtpc_updateShortMessage :
case mtpc_updateShortChatMessage :
case mtpc_updateShort : resultEmpty = false ; break ;
case mtpc_updatesCombined : resultEmpty = result . c_updatesCombined ( ) . vupdates . v . isEmpty ( ) ; break ;
case mtpc_updates : resultEmpty = result . c_updates ( ) . vupdates . v . isEmpty ( ) ; break ;
case mtpc_updatesTooLong :
case mtpc_updateShortSentMessage : LOG ( ( " API Error: Bad updates type in app changelog. " ) ) ; break ;
}
2017-07-04 18:30:46 +03:00
if ( resultEmpty ) {
addLocalChangelogs ( oldAppVersion ) ;
2017-06-30 09:23:31 +03:00
}
2017-06-05 16:33:45 +03:00
} ) . send ( ) ;
unsubscribe ( base : : take ( _changelogSubscription ) ) ;
} ) ;
}
2015-03-19 12:18:19 +03:00
}
2017-07-04 18:30:46 +03:00
void ApiWrap : : addLocalChangelogs ( int oldAppVersion ) {
auto addedSome = false ;
auto addLocalChangelog = [ this , & addedSome ] ( const QString & text ) {
auto textWithEntities = TextWithEntities { text } ;
2017-07-06 14:37:42 +03:00
TextUtilities : : ParseEntities ( textWithEntities , TextParseLinks ) ;
2017-07-04 18:30:46 +03:00
App : : wnd ( ) - > serviceNotification ( textWithEntities , MTP_messageMediaEmpty ( ) , unixtime ( ) ) ;
addedSome = true ;
2017-06-30 13:32:10 +03:00
} ;
2017-07-04 18:30:46 +03:00
if ( cAlphaVersion ( ) | | cBetaVersion ( ) ) {
auto addLocalAlphaChangelog = [ this , oldAppVersion , addLocalChangelog ] ( int changeVersion , const char * changes ) {
if ( oldAppVersion < changeVersion ) {
auto changeVersionString = QString : : number ( changeVersion / 1000000 ) + ' . ' + QString : : number ( ( changeVersion % 1000000 ) / 1000 ) + ( ( changeVersion % 1000 ) ? ( ' . ' + QString : : number ( changeVersion % 1000 ) ) : QString ( ) ) ;
auto text = qsl ( " New in version %1: \n \n " ) . arg ( changeVersionString ) + QString : : fromUtf8 ( changes ) . trimmed ( ) ;
addLocalChangelog ( text ) ;
}
} ;
addLocalAlphaChangelog ( 1001008 , " \xE2 \x80 \x94 Toggle night mode in the main menu. \n " ) ;
addLocalAlphaChangelog ( 1001010 , " \xE2 \x80 \x94 Filter added to channel and supergroup event log. \n \xE2 \x80 \x94 Search by username in privacy exceptions editor fixed. \n \xE2 \x80 \x94 Adding admins in channels fixed. " ) ;
2017-07-06 20:11:25 +03:00
addLocalAlphaChangelog ( 1001011 , " \xE2 \x80 \x94 Send **bold** and __italic__ text in your messages (in addition to already supported `monospace` and ```multiline monospace```). \n \xE2 \x80 \x94 Search in channel and supergroup admin event log. \n \xE2 \x80 \x94 Ban members from right click menu in supergroup admin event log. " ) ;
2017-07-11 21:39:09 +03:00
addLocalAlphaChangelog ( 1001012 , " \xE2 \x80 \x94 Click on forwarded messages bar to change the recipient chat in case you chose a wrong one first. \n \xE2 \x80 \x94 Quickly share posts from channels and media messages from bots. \n \xE2 \x80 \x94 Search in large supergroup members by name. \n \xE2 \x80 \x94 Search in channel members by name if you're a channel admin. \n \xE2 \x80 \x94 Copy links to messages in public supergroups. " ) ;
2017-07-19 11:35:37 +03:00
addLocalAlphaChangelog ( 1001014 , " \xE2 \x80 \x94 Bug fixes and other minor improvements. " ) ;
2017-09-05 20:38:38 +03:00
# ifdef Q_OS_WIN
addLocalAlphaChangelog ( 1001023 , " \xE2 \x80 \x94 See the message author photo and name while searching specific chat messages. \n \xE2 \x80 \x94 Fix \" Send To \" menu action on Windows. " ) ;
# else // Q_OS_WIN
addLocalAlphaChangelog ( 1001023 , " \xE2 \x80 \x94 See the message author photo and name while searching specific chat messages. " ) ;
# endif // Q_OS_WIN
2017-07-04 18:30:46 +03:00
}
if ( ! addedSome ) {
auto text = lng_new_version_wrap ( lt_version , str_const_toString ( AppVersionStr ) , lt_changes , lang ( lng_new_version_minor ) , lt_link , qsl ( " https://desktop.telegram.org/changelog " ) ) . trimmed ( ) ;
addLocalChangelog ( text ) ;
}
2017-06-30 13:32:10 +03:00
}
2017-04-13 20:59:05 +03:00
void ApiWrap : : applyUpdates ( const MTPUpdates & updates , uint64 sentMessageRandomId ) {
App : : main ( ) - > feedUpdates ( updates , sentMessageRandomId ) ;
}
2017-02-26 14:32:13 +03:00
void ApiWrap : : requestMessageData ( ChannelData * channel , MsgId msgId , RequestMessageDataCallback callback ) {
2017-04-06 19:49:42 +03:00
auto & req = ( channel ? _channelMessageDataRequests [ channel ] [ msgId ] : _messageDataRequests [ msgId ] ) ;
2016-05-09 13:07:25 +03:00
if ( callback ) {
2016-11-20 15:54:07 +03:00
req . callbacks . append ( callback ) ;
2016-05-09 13:07:25 +03:00
}
2017-04-06 22:02:40 +03:00
if ( ! req . requestId ) _messageDataResolveDelayed . call ( ) ;
2015-03-19 12:18:19 +03:00
}
2017-04-06 22:02:40 +03:00
QVector < MTPint > ApiWrap : : collectMessageIds ( const MessageDataRequests & requests ) {
auto result = QVector < MTPint > ( ) ;
2015-09-12 14:59:50 +03:00
result . reserve ( requests . size ( ) ) ;
2016-05-09 13:07:25 +03:00
for ( auto i = requests . cbegin ( ) , e = requests . cend ( ) ; i ! = e ; + + i ) {
2017-04-06 22:02:40 +03:00
if ( i . value ( ) . requestId > 0 ) continue ;
2015-09-12 14:59:50 +03:00
result . push_back ( MTP_int ( i . key ( ) ) ) ;
}
return result ;
}
2015-06-28 15:37:10 +03:00
2016-03-10 13:15:21 +03:00
ApiWrap : : MessageDataRequests * ApiWrap : : messageDataRequests ( ChannelData * channel , bool onlyExisting ) {
2015-09-12 14:59:50 +03:00
if ( channel ) {
2016-05-09 13:07:25 +03:00
auto i = _channelMessageDataRequests . find ( channel ) ;
2016-03-10 13:15:21 +03:00
if ( i = = _channelMessageDataRequests . cend ( ) ) {
2015-09-12 14:59:50 +03:00
if ( onlyExisting ) return 0 ;
2016-03-10 13:15:21 +03:00
i = _channelMessageDataRequests . insert ( channel , MessageDataRequests ( ) ) ;
2015-06-28 15:37:10 +03:00
}
2015-09-12 14:59:50 +03:00
return & i . value ( ) ;
2015-06-28 15:37:10 +03:00
}
2016-03-10 13:15:21 +03:00
return & _messageDataRequests ;
2015-09-12 14:59:50 +03:00
}
2016-03-10 13:15:21 +03:00
void ApiWrap : : resolveMessageDatas ( ) {
if ( _messageDataRequests . isEmpty ( ) & & _channelMessageDataRequests . isEmpty ( ) ) return ;
2015-09-12 14:59:50 +03:00
2017-04-06 22:02:40 +03:00
auto ids = collectMessageIds ( _messageDataRequests ) ;
2015-06-28 15:37:10 +03:00
if ( ! ids . isEmpty ( ) ) {
2017-04-06 22:02:40 +03:00
auto requestId = request ( MTPmessages_GetMessages ( MTP_vector < MTPint > ( ids ) ) ) . done ( [ this ] ( const MTPmessages_Messages & result , mtpRequestId requestId ) {
gotMessageDatas ( nullptr , result , requestId ) ;
} ) . after ( kSmallDelayMs ) . send ( ) ;
2016-05-09 13:07:25 +03:00
for ( auto & request : _messageDataRequests ) {
2017-04-06 22:02:40 +03:00
if ( request . requestId > 0 ) continue ;
request . requestId = requestId ;
2015-06-28 15:37:10 +03:00
}
}
2016-05-09 13:07:25 +03:00
for ( auto j = _channelMessageDataRequests . begin ( ) ; j ! = _channelMessageDataRequests . cend ( ) ; ) {
2015-09-12 14:59:50 +03:00
if ( j - > isEmpty ( ) ) {
2016-03-10 13:15:21 +03:00
j = _channelMessageDataRequests . erase ( j ) ;
2015-09-12 14:59:50 +03:00
continue ;
}
2017-04-06 22:02:40 +03:00
auto ids = collectMessageIds ( j . value ( ) ) ;
2015-09-12 14:59:50 +03:00
if ( ! ids . isEmpty ( ) ) {
2017-04-06 22:02:40 +03:00
auto requestId = request ( MTPchannels_GetMessages ( j . key ( ) - > inputChannel , MTP_vector < MTPint > ( ids ) ) ) . done ( [ this , channel = j . key ( ) ] ( const MTPmessages_Messages & result , mtpRequestId requestId ) {
gotMessageDatas ( channel , result , requestId ) ;
} ) . after ( kSmallDelayMs ) . send ( ) ;
2016-05-09 13:07:25 +03:00
for ( auto & request : * j ) {
2017-04-06 22:02:40 +03:00
if ( request . requestId > 0 ) continue ;
request . requestId = requestId ;
2015-09-12 14:59:50 +03:00
}
}
+ + j ;
}
2015-06-28 15:37:10 +03:00
}
2017-04-06 22:02:40 +03:00
void ApiWrap : : gotMessageDatas ( ChannelData * channel , const MTPmessages_Messages & msgs , mtpRequestId requestId ) {
2017-11-20 23:54:05 +04:00
auto handleResult = [ & ] ( auto & & result ) {
App : : feedUsers ( result . vusers ) ;
App : : feedChats ( result . vchats ) ;
App : : feedMsgs ( result . vmessages , NewMessageExisting ) ;
} ;
2015-06-28 15:37:10 +03:00
switch ( msgs . type ( ) ) {
2017-11-20 23:54:05 +04:00
case mtpc_messages_messages :
handleResult ( msgs . c_messages_messages ( ) ) ;
break ;
case mtpc_messages_messagesSlice :
handleResult ( msgs . c_messages_messagesSlice ( ) ) ;
break ;
2015-09-04 16:01:31 +03:00
case mtpc_messages_channelMessages : {
2017-11-20 23:54:05 +04:00
auto & d = msgs . c_messages_channelMessages ( ) ;
2015-09-13 11:41:27 +03:00
if ( channel ) {
channel - > ptsReceived ( d . vpts . v ) ;
} else {
2016-03-05 23:12:55 +02:00
LOG ( ( " App Error: received messages.channelMessages when no channel was passed! (ApiWrap::gotDependencyItem) " ) ) ;
2015-09-19 12:13:21 +03:00
}
2017-11-20 23:54:05 +04:00
handleResult ( d ) ;
2015-09-04 16:01:31 +03:00
} break ;
2017-11-20 23:54:05 +04:00
case mtpc_messages_messagesNotModified :
LOG ( ( " API Error: received messages.messagesNotModified! (ApiWrap::gotDependencyItem) " ) ) ;
break ;
2015-06-28 15:37:10 +03:00
}
2017-04-06 22:02:40 +03:00
auto requests = messageDataRequests ( channel , true ) ;
2015-09-12 14:59:50 +03:00
if ( requests ) {
2016-05-09 13:07:25 +03:00
for ( auto i = requests - > begin ( ) ; i ! = requests - > cend ( ) ; ) {
2017-04-06 22:02:40 +03:00
if ( i . value ( ) . requestId = = requestId ) {
2016-05-09 13:07:25 +03:00
for_const ( auto & callback , i . value ( ) . callbacks ) {
2016-09-26 15:09:59 +03:00
callback ( channel , i . key ( ) ) ;
2015-06-28 15:37:10 +03:00
}
2015-09-12 14:59:50 +03:00
i = requests - > erase ( i ) ;
} else {
+ + i ;
2015-06-28 15:37:10 +03:00
}
2015-09-12 14:59:50 +03:00
}
if ( channel & & requests - > isEmpty ( ) ) {
2016-03-10 13:15:21 +03:00
_channelMessageDataRequests . remove ( channel ) ;
2015-06-28 15:37:10 +03:00
}
}
}
2015-03-19 12:18:19 +03:00
void ApiWrap : : requestFullPeer ( PeerData * peer ) {
2015-06-30 01:09:23 +03:00
if ( ! peer | | _fullPeerRequests . contains ( peer ) ) return ;
2017-04-06 22:02:40 +03:00
auto sendRequest = [ this , peer ] {
auto failHandler = [ this , peer ] ( const RPCError & error ) {
_fullPeerRequests . remove ( peer ) ;
} ;
if ( auto user = peer - > asUser ( ) ) {
return request ( MTPusers_GetFullUser ( user - > inputUser ) ) . done ( [ this , user ] ( const MTPUserFull & result , mtpRequestId requestId ) {
gotUserFull ( user , result , requestId ) ;
} ) . fail ( failHandler ) . send ( ) ;
} else if ( auto chat = peer - > asChat ( ) ) {
return request ( MTPmessages_GetFullChat ( chat - > inputChat ) ) . done ( [ this , peer ] ( const MTPmessages_ChatFull & result , mtpRequestId requestId ) {
gotChatFull ( peer , result , requestId ) ;
} ) . fail ( failHandler ) . send ( ) ;
} else if ( auto channel = peer - > asChannel ( ) ) {
return request ( MTPchannels_GetFullChannel ( channel - > inputChannel ) ) . done ( [ this , peer ] ( const MTPmessages_ChatFull & result , mtpRequestId requestId ) {
gotChatFull ( peer , result , requestId ) ;
} ) . fail ( failHandler ) . send ( ) ;
}
return 0 ;
} ;
if ( auto requestId = sendRequest ( ) ) {
_fullPeerRequests . insert ( peer , requestId ) ;
2015-03-19 12:18:19 +03:00
}
}
2015-10-30 11:57:22 -04:00
void ApiWrap : : processFullPeer ( PeerData * peer , const MTPmessages_ChatFull & result ) {
2017-04-06 22:02:40 +03:00
gotChatFull ( peer , result , mtpRequestId ( 0 ) ) ;
2015-10-30 11:57:22 -04:00
}
2017-04-06 22:02:40 +03:00
void ApiWrap : : processFullPeer ( UserData * user , const MTPUserFull & result ) {
gotUserFull ( user , result , mtpRequestId ( 0 ) ) ;
2015-10-30 11:57:22 -04:00
}
void ApiWrap : : gotChatFull ( PeerData * peer , const MTPmessages_ChatFull & result , mtpRequestId req ) {
2017-03-10 22:46:28 +03:00
auto & d = result . c_messages_chatFull ( ) ;
auto & vc = d . vchats . v ;
auto badVersion = false ;
2015-09-03 13:48:40 +03:00
if ( peer - > isChat ( ) ) {
2017-06-04 14:09:29 +03:00
badVersion = ( ! vc . isEmpty ( ) & & vc [ 0 ] . type ( ) = = mtpc_chat & & vc [ 0 ] . c_chat ( ) . vversion . v < peer - > asChat ( ) - > version ) ;
2015-09-03 13:48:40 +03:00
} else if ( peer - > isChannel ( ) ) {
2017-06-04 14:09:29 +03:00
badVersion = ( ! vc . isEmpty ( ) & & vc [ 0 ] . type ( ) = = mtpc_channel & & vc [ 0 ] . c_channel ( ) . vversion . v < peer - > asChannel ( ) - > version ) ;
2015-09-03 13:48:40 +03:00
}
2015-06-30 01:09:23 +03:00
2016-06-02 16:57:49 +03:00
App : : feedUsers ( d . vusers ) ;
App : : feedChats ( d . vchats ) ;
2015-09-03 13:48:40 +03:00
2017-09-21 22:21:33 +03:00
using UpdateFlag = Notify : : PeerUpdate : : Flag ;
2017-04-06 22:02:40 +03:00
if ( auto chat = peer - > asChat ( ) ) {
2015-09-03 13:48:40 +03:00
if ( d . vfull_chat . type ( ) ! = mtpc_chatFull ) {
LOG ( ( " MTP Error: bad type in gotChatFull for chat: %1 " ) . arg ( d . vfull_chat . type ( ) ) ) ;
return ;
}
2017-03-10 22:46:28 +03:00
auto & f = d . vfull_chat . c_chatFull ( ) ;
2017-08-11 12:42:52 +02:00
App : : feedParticipants ( f . vparticipants , false ) ;
2017-03-10 22:46:28 +03:00
auto & v = f . vbot_info . v ;
for_const ( auto & item , v ) {
switch ( item . type ( ) ) {
2015-09-03 13:48:40 +03:00
case mtpc_botInfo : {
2017-03-10 22:46:28 +03:00
auto & b = item . c_botInfo ( ) ;
if ( auto user = App : : userLoaded ( b . vuser_id . v ) ) {
user - > setBotInfo ( item ) ;
2017-04-06 19:49:42 +03:00
fullPeerUpdated ( ) . notify ( user ) ;
2015-09-03 13:48:40 +03:00
}
} break ;
2015-06-15 20:19:24 +03:00
}
}
2017-10-22 20:06:57 +03:00
auto newPhotoId = PhotoId ( 0 ) ;
2017-04-06 22:02:40 +03:00
if ( auto photo = App : : feedPhoto ( f . vchat_photo ) ) {
2017-09-21 22:21:33 +03:00
newPhotoId = photo - > id ;
2015-09-03 13:48:40 +03:00
photo - > peer = chat ;
2017-09-21 22:21:33 +03:00
}
if ( chat - > photoId ! = newPhotoId ) {
chat - > photoId = newPhotoId ;
Notify : : peerUpdatedDelayed ( chat , UpdateFlag : : PhotoChanged ) ;
2015-03-19 12:18:19 +03:00
}
2016-06-01 16:07:03 +03:00
chat - > setInviteLink ( ( f . vexported_invite . type ( ) = = mtpc_chatInviteExported ) ? qs ( f . vexported_invite . c_chatInviteExported ( ) . vlink ) : QString ( ) ) ;
2017-07-26 14:53:49 +03:00
chat - > fullUpdated ( ) ;
2015-04-30 16:53:36 +03:00
2016-06-01 16:07:03 +03:00
notifySettingReceived ( MTP_inputNotifyPeer ( peer - > input ) , f . vnotify_settings ) ;
2017-04-06 22:02:40 +03:00
} else if ( auto channel = peer - > asChannel ( ) ) {
2015-09-03 13:48:40 +03:00
if ( d . vfull_chat . type ( ) ! = mtpc_channelFull ) {
LOG ( ( " MTP Error: bad type in gotChatFull for channel: %1 " ) . arg ( d . vfull_chat . type ( ) ) ) ;
return ;
}
2017-04-06 22:02:40 +03:00
auto & f = d . vfull_chat . c_channelFull ( ) ;
2017-11-20 23:54:05 +04:00
channel - > setAvailableMinId ( f . vavailable_min_id . v ) ;
2016-06-02 16:02:55 +03:00
auto canViewAdmins = channel - > canViewAdmins ( ) ;
auto canViewMembers = channel - > canViewMembers ( ) ;
2017-08-03 14:52:56 +02:00
auto canEditStickers = channel - > canEditStickers ( ) ;
2016-06-02 16:02:55 +03:00
2017-09-26 14:49:16 +03:00
channel - > setFullFlags ( f . vflags . v ) ;
2017-10-09 22:55:30 +01:00
auto newPhotoId = PhotoId ( 0 ) ;
2017-04-06 22:02:40 +03:00
if ( auto photo = App : : feedPhoto ( f . vchat_photo ) ) {
2017-09-21 22:21:33 +03:00
newPhotoId = photo - > id ;
2015-09-03 13:48:40 +03:00
photo - > peer = channel ;
2017-09-21 22:21:33 +03:00
}
if ( channel - > photoId ! = newPhotoId ) {
channel - > photoId = newPhotoId ;
Notify : : peerUpdatedDelayed ( channel , UpdateFlag : : PhotoChanged ) ;
2015-09-03 13:48:40 +03:00
}
2015-11-13 18:14:33 +03:00
if ( f . has_migrated_from_chat_id ( ) ) {
2017-09-26 14:49:16 +03:00
channel - > addFlags ( MTPDchannel : : Flag : : f_megagroup ) ;
2017-04-06 22:02:40 +03:00
auto cfrom = App : : chat ( peerFromChat ( f . vmigrated_from_chat_id ) ) ;
2015-11-20 21:24:44 +03:00
bool updatedTo = ( cfrom - > migrateToPtr ! = channel ) , updatedFrom = ( channel - > mgInfo - > migrateFromPtr ! = cfrom ) ;
if ( updatedTo ) {
2015-11-13 18:14:33 +03:00
cfrom - > migrateToPtr = channel ;
}
2015-11-20 21:24:44 +03:00
if ( updatedFrom ) {
2015-11-13 18:14:33 +03:00
channel - > mgInfo - > migrateFromPtr = cfrom ;
2017-04-06 22:02:40 +03:00
if ( auto h = App : : historyLoaded ( cfrom - > id ) ) {
if ( auto hto = App : : historyLoaded ( channel - > id ) ) {
2015-11-13 18:14:33 +03:00
if ( ! h - > isEmpty ( ) ) {
h - > clear ( true ) ;
}
2016-04-11 14:59:01 +04:00
if ( hto - > inChatList ( Dialogs : : Mode : : All ) & & h - > inChatList ( Dialogs : : Mode : : All ) ) {
2015-11-13 18:14:33 +03:00
App : : removeDialog ( h ) ;
}
}
}
2015-11-20 21:24:44 +03:00
Notify : : migrateUpdated ( channel ) ;
2015-11-13 18:14:33 +03:00
}
2015-11-20 21:24:44 +03:00
if ( updatedTo ) {
Notify : : migrateUpdated ( cfrom ) ;
2015-11-09 12:51:22 +03:00
}
}
2017-03-10 22:46:28 +03:00
auto & v = f . vbot_info . v ;
for_const ( auto & item , v ) {
switch ( item . type ( ) ) {
2015-11-20 16:34:37 +03:00
case mtpc_botInfo : {
2017-03-10 22:46:28 +03:00
auto & b = item . c_botInfo ( ) ;
if ( auto user = App : : userLoaded ( b . vuser_id . v ) ) {
user - > setBotInfo ( item ) ;
2017-04-06 19:49:42 +03:00
fullPeerUpdated ( ) . notify ( user ) ;
2015-11-20 16:34:37 +03:00
}
} break ;
}
}
2016-05-31 22:27:11 +03:00
channel - > setAbout ( qs ( f . vabout ) ) ;
2016-06-02 16:02:55 +03:00
channel - > setMembersCount ( f . has_participants_count ( ) ? f . vparticipants_count . v : 0 ) ;
channel - > setAdminsCount ( f . has_admins_count ( ) ? f . vadmins_count . v : 0 ) ;
2017-06-09 18:12:02 +02:00
channel - > setRestrictedCount ( f . has_banned_count ( ) ? f . vbanned_count . v : 0 ) ;
2017-04-07 18:07:26 +03:00
channel - > setKickedCount ( f . has_kicked_count ( ) ? f . vkicked_count . v : 0 ) ;
2016-06-01 16:07:03 +03:00
channel - > setInviteLink ( ( f . vexported_invite . type ( ) = = mtpc_chatInviteExported ) ? qs ( f . vexported_invite . c_chatInviteExported ( ) . vlink ) : QString ( ) ) ;
2017-04-06 22:02:40 +03:00
if ( auto h = App : : historyLoaded ( channel - > id ) ) {
2015-09-21 23:57:42 +03:00
if ( h - > inboxReadBefore < f . vread_inbox_max_id . v + 1 ) {
2016-05-27 19:47:46 +03:00
h - > setUnreadCount ( f . vunread_count . v ) ;
2015-09-21 23:57:42 +03:00
h - > inboxReadBefore = f . vread_inbox_max_id . v + 1 ;
}
2016-05-27 19:47:46 +03:00
accumulate_max ( h - > outboxReadBefore , f . vread_outbox_max_id . v + 1 ) ;
2015-09-21 23:57:42 +03:00
}
2016-03-04 17:34:46 +02:00
if ( channel - > isMegagroup ( ) ) {
if ( f . has_pinned_msg_id ( ) ) {
channel - > mgInfo - > pinnedMsgId = f . vpinned_msg_id . v ;
} else {
channel - > mgInfo - > pinnedMsgId = 0 ;
}
2017-08-03 14:52:56 +02:00
auto stickersChanged = ( canEditStickers ! = channel - > canEditStickers ( ) ) ;
auto stickerSet = ( f . has_stickerset ( ) ? & f . vstickerset . c_stickerSet ( ) : nullptr ) ;
auto newSetId = ( stickerSet ? stickerSet - > vid . v : 0 ) ;
auto oldSetId = ( channel - > mgInfo - > stickerSet . type ( ) = = mtpc_inputStickerSetID ) ? channel - > mgInfo - > stickerSet . c_inputStickerSetID ( ) . vid . v : 0 ;
if ( oldSetId ! = newSetId ) {
channel - > mgInfo - > stickerSet = stickerSet ? MTP_inputStickerSetID ( stickerSet - > vid , stickerSet - > vaccess_hash ) : MTP_inputStickerSetEmpty ( ) ;
stickersChanged = true ;
}
if ( stickersChanged ) {
2017-09-21 22:21:33 +03:00
Notify : : peerUpdatedDelayed ( channel , UpdateFlag : : ChannelStickersChanged ) ;
2017-08-03 14:52:56 +02:00
}
2016-03-04 17:34:46 +02:00
}
2015-09-21 23:57:42 +03:00
channel - > fullUpdated ( ) ;
2015-09-03 13:48:40 +03:00
2017-06-09 18:12:02 +02:00
if ( canViewAdmins ! = channel - > canViewAdmins ( )
2017-08-03 14:52:56 +02:00
| | canViewMembers ! = channel - > canViewMembers ( ) ) {
2017-09-21 22:21:33 +03:00
Notify : : peerUpdatedDelayed ( channel , UpdateFlag : : ChannelRightsChanged ) ;
2017-08-03 14:52:56 +02:00
}
2016-06-02 16:02:55 +03:00
2016-06-01 16:07:03 +03:00
notifySettingReceived ( MTP_inputNotifyPeer ( peer - > input ) , f . vnotify_settings ) ;
2015-09-03 13:48:40 +03:00
}
2015-03-19 12:18:19 +03:00
2015-10-30 11:57:22 -04:00
if ( req ) {
2017-06-04 14:09:29 +03:00
auto i = _fullPeerRequests . find ( peer ) ;
2015-10-30 11:57:22 -04:00
if ( i ! = _fullPeerRequests . cend ( ) & & i . value ( ) = = req ) {
_fullPeerRequests . erase ( i ) ;
}
}
2015-06-30 01:09:23 +03:00
if ( badVersion ) {
2017-06-04 14:09:29 +03:00
if ( auto chat = peer - > asChat ( ) ) {
chat - > version = vc [ 0 ] . c_chat ( ) . vversion . v ;
} else if ( auto channel = peer - > asChannel ( ) ) {
channel - > version = vc [ 0 ] . c_channel ( ) . vversion . v ;
2015-09-03 13:48:40 +03:00
}
2015-06-30 01:09:23 +03:00
requestPeer ( peer ) ;
}
2017-04-06 19:49:42 +03:00
fullPeerUpdated ( ) . notify ( peer ) ;
2015-03-19 12:18:19 +03:00
}
2017-04-06 22:02:40 +03:00
void ApiWrap : : gotUserFull ( UserData * user , const MTPUserFull & result , mtpRequestId req ) {
2016-10-24 00:03:10 +03:00
auto & d = result . c_userFull ( ) ;
2017-09-26 14:49:16 +03:00
2016-06-02 16:57:49 +03:00
App : : feedUsers ( MTP_vector < MTPUser > ( 1 , d . vuser ) ) ;
2016-03-04 17:34:46 +02:00
if ( d . has_profile_photo ( ) ) {
App : : feedPhoto ( d . vprofile_photo ) ;
}
2017-04-06 22:02:40 +03:00
App : : feedUserLink ( MTP_int ( peerToUser ( user - > id ) ) , d . vlink . c_contacts_link ( ) . vmy_link , d . vlink . c_contacts_link ( ) . vforeign_link ) ;
2016-02-17 20:14:09 +03:00
if ( App : : main ( ) ) {
2017-04-06 22:02:40 +03:00
notifySettingReceived ( MTP_inputNotifyPeer ( user - > input ) , d . vnotify_settings ) ;
2016-02-17 20:14:09 +03:00
}
2015-03-19 12:18:19 +03:00
2016-03-04 17:34:46 +02:00
if ( d . has_bot_info ( ) ) {
2016-10-24 00:03:10 +03:00
user - > setBotInfo ( d . vbot_info ) ;
2016-03-04 17:34:46 +02:00
} else {
2016-10-24 00:03:10 +03:00
user - > setBotInfoVersion ( - 1 ) ;
2016-03-04 17:34:46 +02:00
}
2016-10-24 00:03:10 +03:00
user - > setBlockStatus ( d . is_blocked ( ) ? UserData : : BlockStatus : : Blocked : UserData : : BlockStatus : : NotBlocked ) ;
2017-04-28 20:16:14 +03:00
user - > setCallsStatus ( d . is_phone_calls_private ( ) ? UserData : : CallsStatus : : Private : d . is_phone_calls_available ( ) ? UserData : : CallsStatus : : Enabled : UserData : : CallsStatus : : Disabled ) ;
2016-10-24 00:03:10 +03:00
user - > setAbout ( d . has_about ( ) ? qs ( d . vabout ) : QString ( ) ) ;
user - > setCommonChatsCount ( d . vcommon_chats_count . v ) ;
2017-07-26 14:53:49 +03:00
user - > fullUpdated ( ) ;
2015-06-10 18:54:24 +03:00
2015-10-30 11:57:22 -04:00
if ( req ) {
2017-04-06 22:02:40 +03:00
auto i = _fullPeerRequests . find ( user ) ;
2015-10-30 11:57:22 -04:00
if ( i ! = _fullPeerRequests . cend ( ) & & i . value ( ) = = req ) {
_fullPeerRequests . erase ( i ) ;
}
}
2017-04-06 22:02:40 +03:00
fullPeerUpdated ( ) . notify ( user ) ;
2015-06-30 01:09:23 +03:00
}
void ApiWrap : : requestPeer ( PeerData * peer ) {
if ( ! peer | | _fullPeerRequests . contains ( peer ) | | _peerRequests . contains ( peer ) ) return ;
2017-04-06 22:02:40 +03:00
auto sendRequest = [ this , peer ] {
auto failHandler = [ this , peer ] ( const RPCError & error ) {
_peerRequests . remove ( peer ) ;
} ;
auto chatHandler = [ this , peer ] ( const MTPmessages_Chats & result ) {
_peerRequests . remove ( peer ) ;
if ( auto chats = Api : : getChatsFromMessagesChats ( result ) ) {
auto & v = chats - > v ;
bool badVersion = false ;
2017-06-04 14:09:29 +03:00
if ( auto chat = peer - > asChat ( ) ) {
badVersion = ( ! v . isEmpty ( ) & & v [ 0 ] . type ( ) = = mtpc_chat & & v [ 0 ] . c_chat ( ) . vversion . v < chat - > version ) ;
} else if ( auto channel = peer - > asChannel ( ) ) {
badVersion = ( ! v . isEmpty ( ) & & v [ 0 ] . type ( ) = = mtpc_channel & & v [ 0 ] . c_channel ( ) . vversion . v < channel - > version ) ;
2017-04-06 22:02:40 +03:00
}
auto chat = App : : feedChats ( * chats ) ;
if ( chat = = peer ) {
if ( badVersion ) {
2017-06-04 14:09:29 +03:00
if ( auto chat = peer - > asChat ( ) ) {
chat - > version = v [ 0 ] . c_chat ( ) . vversion . v ;
} else if ( auto channel = peer - > asChannel ( ) ) {
channel - > version = v [ 0 ] . c_channel ( ) . vversion . v ;
2017-04-06 22:02:40 +03:00
}
requestPeer ( peer ) ;
}
}
}
} ;
if ( auto user = peer - > asUser ( ) ) {
return request ( MTPusers_GetUsers ( MTP_vector < MTPInputUser > ( 1 , user - > inputUser ) ) ) . done ( [ this , user ] ( const MTPVector < MTPUser > & result ) {
_peerRequests . remove ( user ) ;
App : : feedUsers ( result ) ;
} ) . fail ( failHandler ) . send ( ) ;
} else if ( auto chat = peer - > asChat ( ) ) {
return request ( MTPmessages_GetChats ( MTP_vector < MTPint > ( 1 , chat - > inputChat ) ) ) . done ( chatHandler ) . fail ( failHandler ) . send ( ) ;
} else if ( auto channel = peer - > asChannel ( ) ) {
return request ( MTPchannels_GetChannels ( MTP_vector < MTPInputChannel > ( 1 , channel - > inputChannel ) ) ) . done ( chatHandler ) . fail ( failHandler ) . send ( ) ;
}
return 0 ;
} ;
if ( auto requestId = sendRequest ( ) ) {
_peerRequests . insert ( peer , requestId ) ;
2015-06-30 01:09:23 +03:00
}
}
2015-08-07 15:11:50 +03:00
void ApiWrap : : requestPeers ( const QList < PeerData * > & peers ) {
2015-09-17 00:15:13 +03:00
QVector < MTPint > chats ;
QVector < MTPInputChannel > channels ;
2015-08-07 15:11:50 +03:00
QVector < MTPInputUser > users ;
chats . reserve ( peers . size ( ) ) ;
2015-09-17 00:15:13 +03:00
channels . reserve ( peers . size ( ) ) ;
2015-08-07 15:11:50 +03:00
users . reserve ( peers . size ( ) ) ;
for ( QList < PeerData * > : : const_iterator i = peers . cbegin ( ) , e = peers . cend ( ) ; i ! = e ; + + i ) {
if ( ! * i | | _fullPeerRequests . contains ( * i ) | | _peerRequests . contains ( * i ) ) continue ;
2015-09-03 13:48:40 +03:00
if ( ( * i ) - > isUser ( ) ) {
2015-08-07 15:11:50 +03:00
users . push_back ( ( * i ) - > asUser ( ) - > inputUser ) ;
2015-09-03 13:48:40 +03:00
} else if ( ( * i ) - > isChat ( ) ) {
chats . push_back ( ( * i ) - > asChat ( ) - > inputChat ) ;
} else if ( ( * i ) - > isChannel ( ) ) {
2015-09-17 00:15:13 +03:00
channels . push_back ( ( * i ) - > asChannel ( ) - > inputChannel ) ;
2015-08-07 15:11:50 +03:00
}
}
2017-04-06 22:02:40 +03:00
auto handleChats = [ this ] ( const MTPmessages_Chats & result ) {
if ( auto chats = Api : : getChatsFromMessagesChats ( result ) ) {
App : : feedChats ( * chats ) ;
}
} ;
if ( ! chats . isEmpty ( ) ) {
request ( MTPmessages_GetChats ( MTP_vector < MTPint > ( chats ) ) ) . done ( handleChats ) . send ( ) ;
}
if ( ! channels . isEmpty ( ) ) {
request ( MTPchannels_GetChannels ( MTP_vector < MTPInputChannel > ( channels ) ) ) . done ( handleChats ) . send ( ) ;
}
if ( ! users . isEmpty ( ) ) {
request ( MTPusers_GetUsers ( MTP_vector < MTPInputUser > ( users ) ) ) . done ( [ this ] ( const MTPVector < MTPUser > & result ) {
App : : feedUsers ( result ) ;
} ) . send ( ) ;
}
2015-08-07 15:11:50 +03:00
}
2017-04-06 22:02:40 +03:00
void ApiWrap : : requestLastParticipants ( ChannelData * channel , bool fromStart ) {
if ( ! channel | | ! channel - > isMegagroup ( ) ) {
return ;
}
2017-06-04 14:09:29 +03:00
auto needAdmins = channel - > canViewAdmins ( ) ;
2017-04-06 22:02:40 +03:00
auto adminsOutdated = ( channel - > mgInfo - > lastParticipantsStatus & MegagroupInfo : : LastParticipantsAdminsOutdated ) ! = 0 ;
if ( ( needAdmins & & adminsOutdated ) | | channel - > lastParticipantsCountOutdated ( ) ) {
2015-11-19 18:56:29 +03:00
fromStart = true ;
}
2017-04-06 22:02:40 +03:00
auto i = _participantsRequests . find ( channel ) ;
2015-11-19 18:56:29 +03:00
if ( i ! = _participantsRequests . cend ( ) ) {
if ( fromStart & & i . value ( ) < 0 ) { // was not loading from start
_participantsRequests . erase ( i ) ;
} else {
return ;
}
}
2016-01-09 19:24:16 +08:00
2017-11-20 23:54:05 +04:00
auto offset = fromStart ? 0 : channel - > mgInfo - > lastParticipants . size ( ) ;
auto participantsHash = 0 ;
auto requestId = request ( MTPchannels_GetParticipants (
channel - > inputChannel ,
MTP_channelParticipantsRecent ( ) ,
MTP_int ( offset ) ,
MTP_int ( Global : : ChatSizeMax ( ) ) ,
MTP_int ( participantsHash )
) ) . done ( [ this , channel ] ( const MTPchannels_ChannelParticipants & result , mtpRequestId requestId ) {
2017-04-06 22:02:40 +03:00
lastParticipantsDone ( channel , result , requestId ) ;
} ) . fail ( [ this , channel ] ( const RPCError & error , mtpRequestId requestId ) {
2017-11-20 23:54:05 +04:00
if ( _participantsRequests . value ( channel ) = = requestId
| | _participantsRequests . value ( channel ) = = - requestId ) {
2017-04-06 22:02:40 +03:00
_participantsRequests . remove ( channel ) ;
2015-06-30 01:09:23 +03:00
}
2017-04-06 22:02:40 +03:00
} ) . send ( ) ;
2015-06-30 01:09:23 +03:00
2017-04-06 22:02:40 +03:00
_participantsRequests . insert ( channel , fromStart ? requestId : - requestId ) ;
2015-03-19 12:18:19 +03:00
}
2017-04-06 22:02:40 +03:00
void ApiWrap : : requestBots ( ChannelData * channel ) {
if ( ! channel | | ! channel - > isMegagroup ( ) | | _botsRequests . contains ( channel ) ) {
return ;
2016-08-12 18:22:11 +03:00
}
2015-08-07 15:11:50 +03:00
2017-11-20 23:54:05 +04:00
auto offset = 0 ;
auto participantsHash = 0 ;
auto requestId = request ( MTPchannels_GetParticipants (
channel - > inputChannel ,
MTP_channelParticipantsBots ( ) ,
MTP_int ( offset ) ,
MTP_int ( Global : : ChatSizeMax ( ) ) ,
MTP_int ( participantsHash )
) ) . done ( [ this , channel ] ( const MTPchannels_ChannelParticipants & result , mtpRequestId requestId ) {
2017-04-06 22:02:40 +03:00
lastParticipantsDone ( channel , result , requestId ) ;
} ) . fail ( [ this , channel ] ( const RPCError & error , mtpRequestId requestId ) {
if ( _botsRequests . value ( channel ) = = requestId ) {
_botsRequests . remove ( channel ) ;
}
} ) . send ( ) ;
2015-04-04 23:01:34 +03:00
2017-04-06 22:02:40 +03:00
_botsRequests . insert ( channel , requestId ) ;
2015-03-19 12:18:19 +03:00
}
2017-11-20 23:54:05 +04:00
void ApiWrap : : lastParticipantsDone (
ChannelData * peer ,
const MTPchannels_ChannelParticipants & result ,
mtpRequestId requestId ) {
auto bots = ( _botsRequests . value ( peer ) = = requestId ) ;
auto fromStart = false ;
2015-11-19 18:56:29 +03:00
if ( bots ) {
_botsRequests . remove ( peer ) ;
} else {
2017-04-06 22:02:40 +03:00
auto was = _participantsRequests . value ( peer ) ;
if ( was = = requestId ) {
2015-11-19 18:56:29 +03:00
fromStart = true ;
2017-04-06 22:02:40 +03:00
} else if ( was ! = - requestId ) {
2015-11-19 18:56:29 +03:00
return ;
}
2015-11-09 12:51:22 +03:00
_participantsRequests . remove ( peer ) ;
}
2017-11-20 23:54:05 +04:00
if ( ! peer - > mgInfo ) return ;
parseChannelParticipants ( result , [ & ] (
int fullCount ,
const QVector < MTPChannelParticipant > & list ) {
applyLastParticipantsList (
peer ,
fullCount ,
list ,
bots ,
fromStart ) ;
} ) ;
}
2015-11-09 12:51:22 +03:00
2017-11-20 23:54:05 +04:00
void ApiWrap : : applyLastParticipantsList (
ChannelData * peer ,
int fullCount ,
const QVector < MTPChannelParticipant > & list ,
bool bots ,
bool fromStart ) {
auto h = bots ? App : : historyLoaded ( peer - > id ) : nullptr ;
2015-11-19 18:56:29 +03:00
if ( bots ) {
peer - > mgInfo - > bots . clear ( ) ;
peer - > mgInfo - > botStatus = - 1 ;
} else if ( fromStart ) {
peer - > mgInfo - > lastAdmins . clear ( ) ;
peer - > mgInfo - > lastParticipants . clear ( ) ;
peer - > mgInfo - > lastParticipantsStatus = MegagroupInfo : : LastParticipantsUpToDate ;
}
2017-04-06 22:02:40 +03:00
auto added = false ;
auto needBotsInfos = false ;
auto botStatus = peer - > mgInfo - > botStatus ;
auto keyboardBotFound = ! h | | ! h - > lastKeyboardFrom ;
2017-06-09 18:12:02 +02:00
auto emptyAdminRights = MTP_channelAdminRights ( MTP_flags ( 0 ) ) ;
auto emptyRestrictedRights = MTP_channelBannedRights ( MTP_flags ( 0 ) , MTP_int ( 0 ) ) ;
2017-11-20 23:54:05 +04:00
for ( auto & participant : list ) {
2017-04-06 22:02:40 +03:00
auto userId = UserId ( 0 ) ;
2017-06-09 18:12:02 +02:00
auto adminCanEdit = false ;
auto adminRights = emptyAdminRights ;
auto restrictedRights = emptyRestrictedRights ;
2015-11-19 18:56:29 +03:00
2017-04-06 22:02:40 +03:00
switch ( participant . type ( ) ) {
case mtpc_channelParticipant : userId = participant . c_channelParticipant ( ) . vuser_id . v ; break ;
case mtpc_channelParticipantSelf : userId = participant . c_channelParticipantSelf ( ) . vuser_id . v ; break ;
2017-06-09 18:12:02 +02:00
case mtpc_channelParticipantAdmin :
userId = participant . c_channelParticipantAdmin ( ) . vuser_id . v ;
adminCanEdit = participant . c_channelParticipantAdmin ( ) . is_can_edit ( ) ;
adminRights = participant . c_channelParticipantAdmin ( ) . vadmin_rights ;
break ;
case mtpc_channelParticipantBanned :
userId = participant . c_channelParticipantBanned ( ) . vuser_id . v ;
restrictedRights = participant . c_channelParticipantBanned ( ) . vbanned_rights ;
break ;
2017-06-07 15:59:45 +03:00
case mtpc_channelParticipantCreator : userId = participant . c_channelParticipantCreator ( ) . vuser_id . v ; break ;
2015-11-19 18:56:29 +03:00
}
2017-06-04 14:09:29 +03:00
if ( ! userId ) {
continue ;
}
2017-04-06 22:02:40 +03:00
auto u = App : : user ( userId ) ;
2017-06-09 18:12:02 +02:00
if ( participant . type ( ) = = mtpc_channelParticipantCreator ) {
peer - > mgInfo - > creator = u ;
}
2015-11-19 18:56:29 +03:00
if ( bots ) {
if ( u - > botInfo ) {
2016-03-10 18:42:01 +03:00
peer - > mgInfo - > bots . insert ( u ) ;
2015-11-20 16:34:37 +03:00
botStatus = 2 ; // (botStatus > 0/* || !i.key()->botInfo->readsAllHistory*/) ? 2 : 1;
if ( ! u - > botInfo - > inited ) {
needBotsInfos = true ;
}
2015-11-09 12:51:22 +03:00
}
2015-11-24 19:19:18 +03:00
if ( ! keyboardBotFound & & u - > id = = h - > lastKeyboardFrom ) {
keyboardBotFound = true ;
}
2015-11-19 18:56:29 +03:00
} else {
if ( peer - > mgInfo - > lastParticipants . indexOf ( u ) < 0 ) {
2015-11-09 12:51:22 +03:00
peer - > mgInfo - > lastParticipants . push_back ( u ) ;
2017-06-09 18:12:02 +02:00
if ( adminRights . c_channelAdminRights ( ) . vflags . v ) {
peer - > mgInfo - > lastAdmins . insert ( u , MegagroupInfo : : Admin { adminRights , adminCanEdit } ) ;
} else if ( restrictedRights . c_channelBannedRights ( ) . vflags . v ! = 0 ) {
peer - > mgInfo - > lastRestricted . insert ( u , MegagroupInfo : : Restricted { restrictedRights } ) ;
2017-06-07 15:59:45 +03:00
}
2015-11-20 16:34:37 +03:00
if ( u - > botInfo ) {
2016-03-10 18:42:01 +03:00
peer - > mgInfo - > bots . insert ( u ) ;
2015-11-20 16:34:37 +03:00
if ( peer - > mgInfo - > botStatus ! = 0 & & peer - > mgInfo - > botStatus < 2 ) {
peer - > mgInfo - > botStatus = 2 ;
}
}
2015-11-19 18:56:29 +03:00
added = true ;
2015-11-09 12:51:22 +03:00
}
}
}
2015-11-20 16:34:37 +03:00
if ( needBotsInfos ) {
requestFullPeer ( peer ) ;
}
2015-11-24 19:19:18 +03:00
if ( ! keyboardBotFound ) {
h - > clearLastKeyboard ( ) ;
}
2017-11-20 23:54:05 +04:00
int newMembersCount = qMax ( fullCount , list . size ( ) ) ;
2016-06-02 16:02:55 +03:00
if ( newMembersCount > peer - > membersCount ( ) ) {
peer - > setMembersCount ( newMembersCount ) ;
2015-11-19 18:56:29 +03:00
}
2016-06-03 10:20:24 +03:00
if ( ! bots ) {
2017-11-20 23:54:05 +04:00
if ( list . isEmpty ( ) ) {
2016-06-03 10:20:24 +03:00
peer - > setMembersCount ( peer - > mgInfo - > lastParticipants . size ( ) ) ;
}
Notify : : PeerUpdate update ( peer ) ;
update . flags | = Notify : : PeerUpdate : : Flag : : MembersChanged | Notify : : PeerUpdate : : Flag : : AdminsChanged ;
Notify : : peerUpdatedDelayed ( update ) ;
2015-11-19 18:56:29 +03:00
}
2016-06-03 10:20:24 +03:00
2015-11-19 18:56:29 +03:00
peer - > mgInfo - > botStatus = botStatus ;
2017-04-06 19:49:42 +03:00
if ( App : : main ( ) ) fullPeerUpdated ( ) . notify ( peer ) ;
2015-11-09 12:51:22 +03:00
}
2015-09-21 23:57:42 +03:00
void ApiWrap : : requestSelfParticipant ( ChannelData * channel ) {
2017-04-06 22:02:40 +03:00
if ( _selfParticipantRequests . contains ( channel ) ) {
2015-09-21 23:57:42 +03:00
return ;
}
2017-04-06 22:02:40 +03:00
auto requestId = request ( MTPchannels_GetParticipant ( channel - > inputChannel , MTP_inputUserSelf ( ) ) ) . done ( [ this , channel ] ( const MTPchannels_ChannelParticipant & result ) {
_selfParticipantRequests . remove ( channel ) ;
if ( result . type ( ) ! = mtpc_channels_channelParticipant ) {
LOG ( ( " API Error: unknown type in gotSelfParticipant (%1) " ) . arg ( result . type ( ) ) ) ;
channel - > inviter = - 1 ;
if ( App : : main ( ) ) App : : main ( ) - > onSelfParticipantUpdated ( channel ) ;
return ;
}
2015-09-21 23:57:42 +03:00
2017-04-06 22:02:40 +03:00
auto & p = result . c_channels_channelParticipant ( ) ;
App : : feedUsers ( p . vusers ) ;
switch ( p . vparticipant . type ( ) ) {
case mtpc_channelParticipantSelf : {
auto & d = p . vparticipant . c_channelParticipantSelf ( ) ;
channel - > inviter = d . vinviter_id . v ;
channel - > inviteDate = date ( d . vdate ) ;
} break ;
case mtpc_channelParticipantCreator : {
auto & d = p . vparticipant . c_channelParticipantCreator ( ) ;
2017-06-05 16:33:45 +03:00
channel - > inviter = _session - > userId ( ) ;
2017-04-06 22:02:40 +03:00
channel - > inviteDate = date ( MTP_int ( channel - > date ) ) ;
2017-06-09 18:12:02 +02:00
if ( channel - > mgInfo ) {
channel - > mgInfo - > creator = App : : self ( ) ;
}
2017-04-06 22:02:40 +03:00
} break ;
2017-06-04 14:09:29 +03:00
case mtpc_channelParticipantAdmin : {
auto & d = p . vparticipant . c_channelParticipantAdmin ( ) ;
2017-04-06 22:02:40 +03:00
channel - > inviter = d . vinviter_id . v ;
channel - > inviteDate = date ( d . vdate ) ;
} break ;
}
2015-09-21 23:57:42 +03:00
2017-04-06 22:02:40 +03:00
if ( App : : main ( ) ) App : : main ( ) - > onSelfParticipantUpdated ( channel ) ;
} ) . fail ( [ this , channel ] ( const RPCError & error ) {
_selfParticipantRequests . remove ( channel ) ;
if ( error . type ( ) = = qstr ( " USER_NOT_PARTICIPANT " ) ) {
channel - > inviter = - 1 ;
}
} ) . after ( kSmallDelayMs ) . send ( ) ;
2015-09-21 23:57:42 +03:00
2017-04-06 22:02:40 +03:00
_selfParticipantRequests . insert ( channel , requestId ) ;
2015-09-21 23:57:42 +03:00
}
2017-07-06 00:11:49 +03:00
void ApiWrap : : kickParticipant ( PeerData * peer , UserData * user , const MTPChannelBannedRights & currentRights ) {
2017-04-06 22:02:40 +03:00
auto kick = KickRequest ( peer , user ) ;
if ( _kickRequests . contains ( kick ) ) return ;
2015-11-20 22:03:31 +03:00
2017-04-07 18:07:26 +03:00
if ( auto channel = peer - > asChannel ( ) ) {
2017-06-09 18:12:02 +02:00
auto rights = ChannelData : : KickedRestrictedRights ( ) ;
2017-07-06 00:11:49 +03:00
auto requestId = request ( MTPchannels_EditBanned ( channel - > inputChannel , user - > inputUser , rights ) ) . done ( [ this , channel , user , currentRights , rights ] ( const MTPUpdates & result ) {
2017-06-09 18:12:02 +02:00
applyUpdates ( result ) ;
_kickRequests . remove ( KickRequest ( channel , user ) ) ;
2017-07-06 00:11:49 +03:00
channel - > applyEditBanned ( user , currentRights , rights ) ;
2017-06-09 18:12:02 +02:00
} ) . fail ( [ this , kick ] ( const RPCError & error ) {
_kickRequests . remove ( kick ) ;
} ) . send ( ) ;
_kickRequests . insert ( kick , requestId ) ;
2017-04-06 22:02:40 +03:00
}
2015-11-09 12:51:22 +03:00
}
2017-04-07 18:07:26 +03:00
void ApiWrap : : unblockParticipant ( PeerData * peer , UserData * user ) {
auto kick = KickRequest ( peer , user ) ;
if ( _kickRequests . contains ( kick ) ) return ;
if ( auto channel = peer - > asChannel ( ) ) {
2017-06-09 18:12:02 +02:00
auto requestId = request ( MTPchannels_EditBanned ( channel - > inputChannel , user - > inputUser , MTP_channelBannedRights ( MTP_flags ( 0 ) , MTP_int ( 0 ) ) ) ) . done ( [ this , peer , user ] ( const MTPUpdates & result ) {
applyUpdates ( result ) ;
_kickRequests . remove ( KickRequest ( peer , user ) ) ;
if ( auto channel = peer - > asMegagroup ( ) ) {
if ( channel - > kickedCount ( ) > 0 ) {
channel - > setKickedCount ( channel - > kickedCount ( ) - 1 ) ;
} else {
2017-07-26 14:53:49 +03:00
channel - > updateFullForced ( ) ;
2017-06-09 18:12:02 +02:00
}
}
} ) . fail ( [ this , kick ] ( const RPCError & error ) {
_kickRequests . remove ( kick ) ;
} ) . send ( ) ;
_kickRequests . insert ( kick , requestId ) ;
2017-04-07 18:07:26 +03:00
}
}
2017-11-19 18:41:52 +04:00
void ApiWrap : : requestChannelMembersForAdd (
not_null < ChannelData * > channel ,
base : : lambda < void ( const MTPchannels_ChannelParticipants & ) > callback ) {
_channelMembersForAddCallback = std : : move ( callback ) ;
if ( _channelMembersForAdd = = channel ) {
return ;
}
request ( base : : take ( _channelMembersForAddRequestId ) ) . cancel ( ) ;
2017-11-20 23:54:05 +04:00
auto offset = 0 ;
auto participantsHash = 0 ;
2017-11-19 18:41:52 +04:00
_channelMembersForAdd = channel ;
2017-11-20 23:54:05 +04:00
_channelMembersForAddRequestId = request ( MTPchannels_GetParticipants (
channel - > inputChannel ,
MTP_channelParticipantsRecent ( ) ,
MTP_int ( offset ) ,
MTP_int ( Global : : ChatSizeMax ( ) ) ,
MTP_int ( participantsHash )
) ) . done ( [ this ] ( const MTPchannels_ChannelParticipants & result ) {
2017-11-19 18:41:52 +04:00
base : : take ( _channelMembersForAddRequestId ) ;
base : : take ( _channelMembersForAdd ) ;
base : : take ( _channelMembersForAddCallback ) ( result ) ;
} ) . fail ( [ this ] ( const RPCError & error ) {
base : : take ( _channelMembersForAddRequestId ) ;
base : : take ( _channelMembersForAdd ) ;
base : : take ( _channelMembersForAddCallback ) ;
} ) . send ( ) ;
}
2015-06-28 15:37:10 +03:00
void ApiWrap : : scheduleStickerSetRequest ( uint64 setId , uint64 access ) {
if ( ! _stickerSetRequests . contains ( setId ) ) {
_stickerSetRequests . insert ( setId , qMakePair ( access , 0 ) ) ;
}
}
2015-03-19 12:18:19 +03:00
2015-06-28 15:37:10 +03:00
void ApiWrap : : requestStickerSets ( ) {
2017-04-06 22:02:40 +03:00
for ( auto i = _stickerSetRequests . begin ( ) , j = i , e = _stickerSetRequests . end ( ) ; i ! = e ; i = j ) {
2016-01-09 20:51:42 +08:00
+ + j ;
2015-06-28 15:37:10 +03:00
if ( i . value ( ) . second ) continue ;
2017-04-06 22:02:40 +03:00
auto waitMs = ( j = = e ) ? 0 : kSmallDelayMs ;
i . value ( ) . second = request ( MTPmessages_GetStickerSet ( MTP_inputStickerSetID ( MTP_long ( i . key ( ) ) , MTP_long ( i . value ( ) . first ) ) ) ) . done ( [ this , setId = i . key ( ) ] ( const MTPmessages_StickerSet & result ) {
gotStickerSet ( setId , result ) ;
} ) . fail ( [ this , setId = i . key ( ) ] ( const RPCError & error ) {
_stickerSetRequests . remove ( setId ) ;
} ) . after ( waitMs ) . send ( ) ;
2015-06-28 15:37:10 +03:00
}
}
2016-11-22 12:48:13 +03:00
void ApiWrap : : saveStickerSets ( const Stickers : : Order & localOrder , const Stickers : : Order & localRemoved ) {
for ( auto requestId : base : : take ( _stickerSetDisenableRequests ) ) {
2017-04-06 22:02:40 +03:00
request ( requestId ) . cancel ( ) ;
2016-11-22 12:48:13 +03:00
}
2017-04-06 22:02:40 +03:00
request ( base : : take ( _stickersReorderRequestId ) ) . cancel ( ) ;
request ( base : : take ( _stickersClearRecentRequestId ) ) . cancel ( ) ;
2016-11-22 12:48:13 +03:00
2017-08-02 18:07:28 +03:00
auto writeInstalled = true , writeRecent = false , writeCloudRecent = false , writeFaved = false , writeArchived = false ;
2016-11-22 12:48:13 +03:00
auto & recent = cGetRecentStickers ( ) ;
2017-11-05 21:07:27 +04:00
auto & sets = Auth ( ) . data ( ) . stickerSetsRef ( ) ;
2016-11-22 12:48:13 +03:00
_stickersOrder = localOrder ;
for_const ( auto removedSetId , localRemoved ) {
if ( removedSetId = = Stickers : : CloudRecentSetId ) {
if ( sets . remove ( Stickers : : CloudRecentSetId ) ! = 0 ) {
writeCloudRecent = true ;
}
if ( sets . remove ( Stickers : : CustomSetId ) ) {
writeInstalled = true ;
}
if ( ! recent . isEmpty ( ) ) {
recent . clear ( ) ;
writeRecent = true ;
}
2017-04-06 22:02:40 +03:00
_stickersClearRecentRequestId = request ( MTPmessages_ClearRecentStickers ( MTP_flags ( 0 ) ) ) . done ( [ this ] ( const MTPBool & result ) {
_stickersClearRecentRequestId = 0 ;
} ) . fail ( [ this ] ( const RPCError & error ) {
_stickersClearRecentRequestId = 0 ;
} ) . send ( ) ;
2016-11-22 12:48:13 +03:00
continue ;
}
auto it = sets . find ( removedSetId ) ;
if ( it ! = sets . cend ( ) ) {
for ( auto i = recent . begin ( ) ; i ! = recent . cend ( ) ; ) {
if ( it - > stickers . indexOf ( i - > first ) > = 0 ) {
i = recent . erase ( i ) ;
writeRecent = true ;
} else {
+ + i ;
}
}
if ( ! ( it - > flags & MTPDstickerSet : : Flag : : f_archived ) ) {
MTPInputStickerSet setId = ( it - > id & & it - > access ) ? MTP_inputStickerSetID ( MTP_long ( it - > id ) , MTP_long ( it - > access ) ) : MTP_inputStickerSetShortName ( MTP_string ( it - > shortName ) ) ;
2017-04-06 22:02:40 +03:00
auto requestId = request ( MTPmessages_UninstallStickerSet ( setId ) ) . done ( [ this ] ( const MTPBool & result , mtpRequestId requestId ) {
stickerSetDisenabled ( requestId ) ;
} ) . fail ( [ this ] ( const RPCError & error , mtpRequestId requestId ) {
stickerSetDisenabled ( requestId ) ;
} ) . after ( kSmallDelayMs ) . send ( ) ;
_stickerSetDisenableRequests . insert ( requestId ) ;
2017-11-05 21:07:27 +04:00
int removeIndex = Auth ( ) . data ( ) . stickerSetsOrder ( ) . indexOf ( it - > id ) ;
if ( removeIndex > = 0 ) Auth ( ) . data ( ) . stickerSetsOrderRef ( ) . removeAt ( removeIndex ) ;
2016-11-22 12:48:13 +03:00
if ( ! ( it - > flags & MTPDstickerSet_ClientFlag : : f_featured ) & & ! ( it - > flags & MTPDstickerSet_ClientFlag : : f_special ) ) {
sets . erase ( it ) ;
} else {
if ( it - > flags & MTPDstickerSet : : Flag : : f_archived ) {
writeArchived = true ;
}
it - > flags & = ~ ( MTPDstickerSet : : Flag : : f_installed | MTPDstickerSet : : Flag : : f_archived ) ;
}
}
}
}
// Clear all installed flags, set only for sets from order.
for ( auto & set : sets ) {
if ( ! ( set . flags & MTPDstickerSet : : Flag : : f_archived ) ) {
set . flags & = ~ MTPDstickerSet : : Flag : : f_installed ;
}
}
2017-11-05 21:07:27 +04:00
auto & order = Auth ( ) . data ( ) . stickerSetsOrderRef ( ) ;
2016-11-22 12:48:13 +03:00
order . clear ( ) ;
for_const ( auto setId , _stickersOrder ) {
auto it = sets . find ( setId ) ;
if ( it ! = sets . cend ( ) ) {
if ( ( it - > flags & MTPDstickerSet : : Flag : : f_archived ) & & ! localRemoved . contains ( it - > id ) ) {
MTPInputStickerSet mtpSetId = ( it - > id & & it - > access ) ? MTP_inputStickerSetID ( MTP_long ( it - > id ) , MTP_long ( it - > access ) ) : MTP_inputStickerSetShortName ( MTP_string ( it - > shortName ) ) ;
2017-04-06 22:02:40 +03:00
auto requestId = request ( MTPmessages_InstallStickerSet ( mtpSetId , MTP_boolFalse ( ) ) ) . done ( [ this ] ( const MTPmessages_StickerSetInstallResult & result , mtpRequestId requestId ) {
stickerSetDisenabled ( requestId ) ;
} ) . fail ( [ this ] ( const RPCError & error , mtpRequestId requestId ) {
stickerSetDisenabled ( requestId ) ;
} ) . after ( kSmallDelayMs ) . send ( ) ;
_stickerSetDisenableRequests . insert ( requestId ) ;
2016-11-22 12:48:13 +03:00
it - > flags & = ~ MTPDstickerSet : : Flag : : f_archived ;
writeArchived = true ;
}
order . push_back ( setId ) ;
it - > flags | = MTPDstickerSet : : Flag : : f_installed ;
}
}
for ( auto it = sets . begin ( ) ; it ! = sets . cend ( ) ; ) {
if ( ( it - > flags & MTPDstickerSet_ClientFlag : : f_featured )
| | ( it - > flags & MTPDstickerSet : : Flag : : f_installed )
| | ( it - > flags & MTPDstickerSet : : Flag : : f_archived )
| | ( it - > flags & MTPDstickerSet_ClientFlag : : f_special ) ) {
+ + it ;
} else {
it = sets . erase ( it ) ;
}
}
if ( writeInstalled ) Local : : writeInstalledStickers ( ) ;
if ( writeRecent ) Local : : writeUserSettings ( ) ;
if ( writeArchived ) Local : : writeArchivedStickers ( ) ;
if ( writeCloudRecent ) Local : : writeRecentStickers ( ) ;
2017-08-02 18:07:28 +03:00
if ( writeFaved ) Local : : writeFavedStickers ( ) ;
2017-11-05 21:07:27 +04:00
Auth ( ) . data ( ) . markStickersUpdated ( ) ;
2016-11-22 12:48:13 +03:00
2017-11-05 21:07:27 +04:00
if ( _stickerSetDisenableRequests . empty ( ) ) {
2016-11-22 12:48:13 +03:00
stickersSaveOrder ( ) ;
} else {
2017-04-06 22:02:40 +03:00
requestSendDelayed ( ) ;
2016-11-22 12:48:13 +03:00
}
}
2017-04-06 22:02:40 +03:00
void ApiWrap : : stickerSetDisenabled ( mtpRequestId requestId ) {
_stickerSetDisenableRequests . remove ( requestId ) ;
2017-11-05 21:07:27 +04:00
if ( _stickerSetDisenableRequests . empty ( ) ) {
2017-04-06 22:02:40 +03:00
stickersSaveOrder ( ) ;
}
} ;
2016-05-25 20:59:21 +03:00
void ApiWrap : : joinChannel ( ChannelData * channel ) {
if ( channel - > amIn ( ) ) {
2017-04-06 22:02:40 +03:00
Notify : : peerUpdatedDelayed ( channel , Notify : : PeerUpdate : : Flag : : ChannelAmIn ) ;
2016-05-25 20:59:21 +03:00
} else if ( ! _channelAmInRequests . contains ( channel ) ) {
2017-04-06 22:02:40 +03:00
auto requestId = request ( MTPchannels_JoinChannel ( channel - > inputChannel ) ) . done ( [ this , channel ] ( const MTPUpdates & result ) {
_channelAmInRequests . remove ( channel ) ;
2017-04-13 20:59:05 +03:00
applyUpdates ( result ) ;
2017-04-06 22:02:40 +03:00
} ) . fail ( [ this , channel ] ( const RPCError & error ) {
if ( error . type ( ) = = qstr ( " CHANNELS_TOO_MUCH " ) ) {
Ui : : show ( Box < InformBox > ( lang ( lng_join_channel_error ) ) ) ;
}
_channelAmInRequests . remove ( channel ) ;
} ) . send ( ) ;
2016-05-25 20:59:21 +03:00
_channelAmInRequests . insert ( channel , requestId ) ;
}
}
void ApiWrap : : leaveChannel ( ChannelData * channel ) {
if ( ! channel - > amIn ( ) ) {
2017-04-06 22:02:40 +03:00
Notify : : peerUpdatedDelayed ( channel , Notify : : PeerUpdate : : Flag : : ChannelAmIn ) ;
2016-05-25 20:59:21 +03:00
} else if ( ! _channelAmInRequests . contains ( channel ) ) {
2017-04-06 22:02:40 +03:00
auto requestId = request ( MTPchannels_LeaveChannel ( channel - > inputChannel ) ) . done ( [ this , channel ] ( const MTPUpdates & result ) {
_channelAmInRequests . remove ( channel ) ;
2017-04-13 20:59:05 +03:00
applyUpdates ( result ) ;
2017-04-06 22:02:40 +03:00
} ) . fail ( [ this , channel ] ( const RPCError & error ) {
_channelAmInRequests . remove ( channel ) ;
} ) . send ( ) ;
2016-05-25 20:59:21 +03:00
2017-04-06 22:02:40 +03:00
_channelAmInRequests . insert ( channel , requestId ) ;
2016-06-07 22:59:39 +03:00
}
2016-05-25 20:59:21 +03:00
}
2016-06-01 23:05:37 +03:00
void ApiWrap : : blockUser ( UserData * user ) {
if ( user - > isBlocked ( ) ) {
Notify : : peerUpdatedDelayed ( user , Notify : : PeerUpdate : : Flag : : UserIsBlocked ) ;
} else if ( ! _blockRequests . contains ( user ) ) {
2017-04-06 22:02:40 +03:00
auto requestId = request ( MTPcontacts_Block ( user - > inputUser ) ) . done ( [ this , user ] ( const MTPBool & result ) {
_blockRequests . remove ( user ) ;
user - > setBlockStatus ( UserData : : BlockStatus : : Blocked ) ;
} ) . fail ( [ this , user ] ( const RPCError & error ) {
_blockRequests . remove ( user ) ;
} ) . send ( ) ;
2016-06-01 23:05:37 +03:00
_blockRequests . insert ( user , requestId ) ;
}
}
void ApiWrap : : unblockUser ( UserData * user ) {
if ( ! user - > isBlocked ( ) ) {
Notify : : peerUpdatedDelayed ( user , Notify : : PeerUpdate : : Flag : : UserIsBlocked ) ;
} else if ( ! _blockRequests . contains ( user ) ) {
2017-04-06 22:02:40 +03:00
auto requestId = request ( MTPcontacts_Unblock ( user - > inputUser ) ) . done ( [ this , user ] ( const MTPBool & result ) {
_blockRequests . remove ( user ) ;
user - > setBlockStatus ( UserData : : BlockStatus : : NotBlocked ) ;
} ) . fail ( [ this , user ] ( const RPCError & error ) {
_blockRequests . remove ( user ) ;
} ) . send ( ) ;
2016-06-01 23:05:37 +03:00
_blockRequests . insert ( user , requestId ) ;
}
}
2016-06-01 16:07:03 +03:00
void ApiWrap : : exportInviteLink ( PeerData * peer ) {
if ( _exportInviteRequests . contains ( peer ) ) {
return ;
}
2017-04-06 22:02:40 +03:00
auto sendRequest = [ this , peer ] {
auto exportFail = [ this , peer ] ( const RPCError & error ) {
_exportInviteRequests . remove ( peer ) ;
} ;
if ( auto chat = peer - > asChat ( ) ) {
return request ( MTPmessages_ExportChatInvite ( chat - > inputChat ) ) . done ( [ this , chat ] ( const MTPExportedChatInvite & result ) {
_exportInviteRequests . remove ( chat ) ;
chat - > setInviteLink ( ( result . type ( ) = = mtpc_chatInviteExported ) ? qs ( result . c_chatInviteExported ( ) . vlink ) : QString ( ) ) ;
} ) . fail ( exportFail ) . send ( ) ;
} else if ( auto channel = peer - > asChannel ( ) ) {
return request ( MTPchannels_ExportInvite ( channel - > inputChannel ) ) . done ( [ this , channel ] ( const MTPExportedChatInvite & result ) {
_exportInviteRequests . remove ( channel ) ;
channel - > setInviteLink ( ( result . type ( ) = = mtpc_chatInviteExported ) ? qs ( result . c_chatInviteExported ( ) . vlink ) : QString ( ) ) ;
} ) . fail ( exportFail ) . send ( ) ;
}
return 0 ;
} ;
if ( auto requestId = sendRequest ( ) ) {
_exportInviteRequests . insert ( peer , requestId ) ;
2016-06-01 16:07:03 +03:00
}
}
void ApiWrap : : requestNotifySetting ( PeerData * peer ) {
if ( _notifySettingRequests . contains ( peer ) ) return ;
2017-04-06 22:02:40 +03:00
auto notifyPeer = MTP_inputNotifyPeer ( peer - > input ) ;
auto requestId = request ( MTPaccount_GetNotifySettings ( notifyPeer ) ) . done ( [ this , notifyPeer , peer ] ( const MTPPeerNotifySettings & result ) {
notifySettingReceived ( notifyPeer , result ) ;
_notifySettingRequests . remove ( peer ) ;
} ) . fail ( [ this , notifyPeer , peer ] ( const RPCError & error ) {
notifySettingReceived ( notifyPeer , MTP_peerNotifySettingsEmpty ( ) ) ;
_notifySettingRequests . remove ( peer ) ;
} ) . send ( ) ;
2016-06-01 16:07:03 +03:00
_notifySettingRequests . insert ( peer , requestId ) ;
}
2016-06-07 22:59:39 +03:00
void ApiWrap : : saveDraftToCloudDelayed ( History * history ) {
_draftsSaveRequestIds . insert ( history , 0 ) ;
if ( ! _draftsSaveTimer . isActive ( ) ) {
2017-04-07 15:10:10 +03:00
_draftsSaveTimer . callOnce ( kSaveCloudDraftTimeout ) ;
2016-06-07 22:59:39 +03:00
}
}
2017-03-17 20:19:46 +03:00
void ApiWrap : : savePrivacy ( const MTPInputPrivacyKey & key , QVector < MTPInputPrivacyRule > & & rules ) {
auto keyTypeId = key . type ( ) ;
auto it = _privacySaveRequests . find ( keyTypeId ) ;
if ( it ! = _privacySaveRequests . cend ( ) ) {
2017-04-06 22:02:40 +03:00
request ( it . value ( ) ) . cancel ( ) ;
2017-03-17 20:19:46 +03:00
_privacySaveRequests . erase ( it ) ;
}
2017-04-06 22:02:40 +03:00
auto requestId = request ( MTPaccount_SetPrivacy ( key , MTP_vector < MTPInputPrivacyRule > ( std : : move ( rules ) ) ) ) . done ( [ this , keyTypeId ] ( const MTPaccount_PrivacyRules & result ) {
Expects ( result . type ( ) = = mtpc_account_privacyRules ) ;
auto & rules = result . c_account_privacyRules ( ) ;
App : : feedUsers ( rules . vusers ) ;
_privacySaveRequests . remove ( keyTypeId ) ;
handlePrivacyChange ( keyTypeId , rules . vrules ) ;
} ) . fail ( [ this , keyTypeId ] ( const RPCError & error ) {
_privacySaveRequests . remove ( keyTypeId ) ;
} ) . send ( ) ;
2017-03-17 20:19:46 +03:00
2017-04-06 22:02:40 +03:00
_privacySaveRequests . insert ( keyTypeId , requestId ) ;
2017-03-17 20:19:46 +03:00
}
void ApiWrap : : handlePrivacyChange ( mtpTypeId keyTypeId , const MTPVector < MTPPrivacyRule > & rules ) {
if ( keyTypeId = = mtpc_privacyKeyStatusTimestamp ) {
enum class Rule {
Unknown ,
Allow ,
Disallow ,
} ;
auto userRules = QMap < UserId , Rule > ( ) ;
auto contactsRule = Rule : : Unknown ;
auto everyoneRule = Rule : : Unknown ;
for ( auto & rule : rules . v ) {
auto type = rule . type ( ) ;
if ( type ! = mtpc_privacyValueAllowAll & & type ! = mtpc_privacyValueDisallowAll & & contactsRule ! = Rule : : Unknown ) {
// This is simplified: we ignore per-user rules that come after a contacts rule.
// But none of the official apps provide such complicated rule sets, so its fine.
continue ;
}
switch ( type ) {
case mtpc_privacyValueAllowAll : everyoneRule = Rule : : Allow ; break ;
case mtpc_privacyValueDisallowAll : everyoneRule = Rule : : Disallow ; break ;
case mtpc_privacyValueAllowContacts : contactsRule = Rule : : Allow ; break ;
case mtpc_privacyValueDisallowContacts : contactsRule = Rule : : Disallow ; break ;
case mtpc_privacyValueAllowUsers : {
for_const ( auto & userId , rule . c_privacyValueAllowUsers ( ) . vusers . v ) {
if ( ! userRules . contains ( userId . v ) ) {
userRules . insert ( userId . v , Rule : : Allow ) ;
}
}
} break ;
case mtpc_privacyValueDisallowUsers : {
for_const ( auto & userId , rule . c_privacyValueDisallowUsers ( ) . vusers . v ) {
if ( ! userRules . contains ( userId . v ) ) {
userRules . insert ( userId . v , Rule : : Disallow ) ;
}
}
} break ;
}
if ( everyoneRule ! = Rule : : Unknown ) {
break ;
}
}
auto now = unixtime ( ) ;
App : : enumerateUsers ( [ & userRules , contactsRule , everyoneRule , now ] ( UserData * user ) {
if ( user - > isSelf ( ) | | user - > loadedStatus ! = PeerData : : FullLoaded ) {
return ;
}
if ( user - > onlineTill < = 0 ) {
return ;
}
if ( user - > onlineTill + 3 * 86400 > = now ) {
user - > onlineTill = - 2 ; // recently
} else if ( user - > onlineTill + 7 * 86400 > = now ) {
user - > onlineTill = - 3 ; // last week
} else if ( user - > onlineTill + 30 * 86400 > = now ) {
user - > onlineTill = - 4 ; // last month
} else {
user - > onlineTill = 0 ;
}
Notify : : peerUpdatedDelayed ( user , Notify : : PeerUpdate : : Flag : : UserOnlineChanged ) ;
} ) ;
if ( _contactsStatusesRequestId ) {
2017-04-06 22:02:40 +03:00
request ( _contactsStatusesRequestId ) . cancel ( ) ;
2017-03-17 20:19:46 +03:00
}
2017-04-06 22:02:40 +03:00
_contactsStatusesRequestId = request ( MTPcontacts_GetStatuses ( ) ) . done ( [ this ] ( const MTPVector < MTPContactStatus > & result ) {
_contactsStatusesRequestId = 0 ;
for_const ( auto & item , result . v ) {
2017-08-17 12:06:26 +03:00
Assert ( item . type ( ) = = mtpc_contactStatus ) ;
2017-04-06 22:02:40 +03:00
auto & data = item . c_contactStatus ( ) ;
if ( auto user = App : : userLoaded ( data . vuser_id . v ) ) {
auto oldOnlineTill = user - > onlineTill ;
auto newOnlineTill = onlineTillFromStatus ( data . vstatus , oldOnlineTill ) ;
if ( oldOnlineTill ! = newOnlineTill ) {
user - > onlineTill = newOnlineTill ;
Notify : : peerUpdatedDelayed ( user , Notify : : PeerUpdate : : Flag : : UserOnlineChanged ) ;
}
}
}
} ) . fail ( [ this ] ( const RPCError & error ) {
_contactsStatusesRequestId = 0 ;
} ) . send ( ) ;
2017-03-17 20:19:46 +03:00
}
}
int ApiWrap : : onlineTillFromStatus ( const MTPUserStatus & status , int currentOnlineTill ) {
switch ( status . type ( ) ) {
case mtpc_userStatusEmpty : return 0 ;
case mtpc_userStatusRecently : return ( currentOnlineTill > - 10 ) ? - 2 : currentOnlineTill ; // don't modify pseudo-online
case mtpc_userStatusLastWeek : return - 3 ;
case mtpc_userStatusLastMonth : return - 4 ;
case mtpc_userStatusOffline : return status . c_userStatusOffline ( ) . vwas_online . v ;
case mtpc_userStatusOnline : return status . c_userStatusOnline ( ) . vexpires . v ;
}
Unexpected ( " Bad UserStatus type. " ) ;
}
2016-06-07 22:59:39 +03:00
void ApiWrap : : saveDraftsToCloud ( ) {
for ( auto i = _draftsSaveRequestIds . begin ( ) , e = _draftsSaveRequestIds . end ( ) ; i ! = e ; + + i ) {
if ( i . value ( ) ) continue ; // sent already
auto history = i . key ( ) ;
auto cloudDraft = history - > cloudDraft ( ) ;
auto localDraft = history - > localDraft ( ) ;
if ( cloudDraft & & cloudDraft - > saveRequestId ) {
2017-04-06 22:02:40 +03:00
request ( base : : take ( cloudDraft - > saveRequestId ) ) . cancel ( ) ;
2016-06-07 22:59:39 +03:00
}
cloudDraft = history - > createCloudDraft ( localDraft ) ;
2017-03-25 18:42:01 +03:00
auto flags = MTPmessages_SaveDraft : : Flags ( 0 ) ;
2016-06-07 22:59:39 +03:00
auto & textWithTags = cloudDraft - > textWithTags ;
if ( cloudDraft - > previewCancelled ) {
flags | = MTPmessages_SaveDraft : : Flag : : f_no_webpage ;
}
if ( cloudDraft - > msgId ) {
flags | = MTPmessages_SaveDraft : : Flag : : f_reply_to_msg_id ;
}
if ( ! textWithTags . tags . isEmpty ( ) ) {
flags | = MTPmessages_SaveDraft : : Flag : : f_entities ;
}
2017-07-06 14:37:42 +03:00
auto entities = TextUtilities : : EntitiesToMTP ( ConvertTextTagsToEntities ( textWithTags . tags ) , TextUtilities : : ConvertOption : : SkipLocal ) ;
2017-04-06 22:02:40 +03:00
cloudDraft - > saveRequestId = request ( MTPmessages_SaveDraft ( MTP_flags ( flags ) , MTP_int ( cloudDraft - > msgId ) , history - > peer - > input , MTP_string ( textWithTags . text ) , entities ) ) . done ( [ this , history ] ( const MTPBool & result , mtpRequestId requestId ) {
if ( auto cloudDraft = history - > cloudDraft ( ) ) {
if ( cloudDraft - > saveRequestId = = requestId ) {
cloudDraft - > saveRequestId = 0 ;
history - > draftSavedToCloud ( ) ;
}
}
auto i = _draftsSaveRequestIds . find ( history ) ;
if ( i ! = _draftsSaveRequestIds . cend ( ) & & i . value ( ) = = requestId ) {
_draftsSaveRequestIds . remove ( history ) ;
2017-04-29 23:06:32 +03:00
checkQuitPreventFinished ( ) ;
2017-04-06 22:02:40 +03:00
}
} ) . fail ( [ this , history ] ( const RPCError & error , mtpRequestId requestId ) {
if ( auto cloudDraft = history - > cloudDraft ( ) ) {
if ( cloudDraft - > saveRequestId = = requestId ) {
history - > clearCloudDraft ( ) ;
}
}
auto i = _draftsSaveRequestIds . find ( history ) ;
if ( i ! = _draftsSaveRequestIds . cend ( ) & & i . value ( ) = = requestId ) {
_draftsSaveRequestIds . remove ( history ) ;
2017-04-29 23:06:32 +03:00
checkQuitPreventFinished ( ) ;
2017-04-06 22:02:40 +03:00
}
} ) . send ( ) ;
2016-06-07 22:59:39 +03:00
i . value ( ) = cloudDraft - > saveRequestId ;
}
2017-04-29 23:06:32 +03:00
}
bool ApiWrap : : isQuitPrevent ( ) {
2016-06-07 22:59:39 +03:00
if ( _draftsSaveRequestIds . isEmpty ( ) ) {
2017-04-29 23:06:32 +03:00
return false ;
}
LOG ( ( " ApiWrap prevents quit, saving drafts... " ) ) ;
saveDraftsToCloud ( ) ;
return true ;
}
void ApiWrap : : checkQuitPreventFinished ( ) {
if ( _draftsSaveRequestIds . isEmpty ( ) ) {
if ( App : : quitting ( ) ) {
LOG ( ( " ApiWrap doesn't prevent quit any more. " ) ) ;
}
Messenger : : Instance ( ) . quitPreventFinished ( ) ;
2016-06-07 22:59:39 +03:00
}
}
2016-06-01 16:07:03 +03:00
PeerData * ApiWrap : : notifySettingReceived ( MTPInputNotifyPeer notifyPeer , const MTPPeerNotifySettings & settings ) {
PeerData * requestedPeer = nullptr ;
switch ( notifyPeer . type ( ) ) {
case mtpc_inputNotifyAll : App : : main ( ) - > applyNotifySetting ( MTP_notifyAll ( ) , settings ) ; break ;
case mtpc_inputNotifyUsers : App : : main ( ) - > applyNotifySetting ( MTP_notifyUsers ( ) , settings ) ; break ;
case mtpc_inputNotifyChats : App : : main ( ) - > applyNotifySetting ( MTP_notifyChats ( ) , settings ) ; break ;
case mtpc_inputNotifyPeer : {
auto & peer = notifyPeer . c_inputNotifyPeer ( ) . vpeer ;
switch ( peer . type ( ) ) {
case mtpc_inputPeerEmpty : App : : main ( ) - > applyNotifySetting ( MTP_notifyPeer ( MTP_peerUser ( MTP_int ( 0 ) ) ) , settings ) ; break ;
case mtpc_inputPeerSelf : requestedPeer = App : : self ( ) ; break ;
case mtpc_inputPeerUser : requestedPeer = App : : user ( peerFromUser ( peer . c_inputPeerUser ( ) . vuser_id ) ) ; break ;
case mtpc_inputPeerChat : requestedPeer = App : : chat ( peerFromChat ( peer . c_inputPeerChat ( ) . vchat_id ) ) ; break ;
case mtpc_inputPeerChannel : requestedPeer = App : : channel ( peerFromChannel ( peer . c_inputPeerChannel ( ) . vchannel_id ) ) ; break ;
}
if ( requestedPeer ) {
App : : main ( ) - > applyNotifySetting ( MTP_notifyPeer ( peerToMTP ( requestedPeer - > id ) ) , settings ) ;
}
} break ;
}
2017-06-05 16:33:45 +03:00
_session - > notifications ( ) . checkDelayed ( ) ;
2016-06-01 16:07:03 +03:00
return requestedPeer ;
}
2015-06-28 15:37:10 +03:00
void ApiWrap : : gotStickerSet ( uint64 setId , const MTPmessages_StickerSet & result ) {
_stickerSetRequests . remove ( setId ) ;
2017-08-03 14:52:56 +02:00
Stickers : : FeedSetFull ( result ) ;
2015-06-28 15:37:10 +03:00
}
void ApiWrap : : requestWebPageDelayed ( WebPageData * page ) {
if ( page - > pendingTill < = 0 ) return ;
_webPagesPending . insert ( page , 0 ) ;
2017-04-07 15:10:10 +03:00
auto left = ( page - > pendingTill - unixtime ( ) ) * 1000 ;
2015-06-28 15:37:10 +03:00
if ( ! _webPagesTimer . isActive ( ) | | left < = _webPagesTimer . remainingTime ( ) ) {
2017-04-07 15:10:10 +03:00
_webPagesTimer . callOnce ( ( left < 0 ? 0 : left ) + 1 ) ;
2015-03-19 12:18:19 +03:00
}
}
2015-06-28 15:37:10 +03:00
void ApiWrap : : clearWebPageRequest ( WebPageData * page ) {
_webPagesPending . remove ( page ) ;
2017-04-07 15:10:10 +03:00
if ( _webPagesPending . isEmpty ( ) & & _webPagesTimer . isActive ( ) ) {
_webPagesTimer . cancel ( ) ;
}
2015-06-28 15:37:10 +03:00
}
void ApiWrap : : clearWebPageRequests ( ) {
_webPagesPending . clear ( ) ;
2017-04-07 15:10:10 +03:00
_webPagesTimer . cancel ( ) ;
2015-06-28 15:37:10 +03:00
}
2015-04-04 23:01:34 +03:00
void ApiWrap : : resolveWebPages ( ) {
2017-04-06 22:02:40 +03:00
auto ids = QVector < MTPint > ( ) ; // temp_req_id = -1
using IndexAndMessageIds = QPair < int32 , QVector < MTPint > > ;
2016-09-27 16:37:18 +03:00
using MessageIdsByChannel = QMap < ChannelData * , IndexAndMessageIds > ;
2015-09-12 14:59:50 +03:00
MessageIdsByChannel idsByChannel ; // temp_req_id = -index - 2
2016-09-27 16:37:18 +03:00
auto & items = App : : webPageItems ( ) ;
2015-04-04 23:01:34 +03:00
ids . reserve ( _webPagesPending . size ( ) ) ;
int32 t = unixtime ( ) , m = INT_MAX ;
2016-09-27 16:37:18 +03:00
for ( auto i = _webPagesPending . begin ( ) ; i ! = _webPagesPending . cend ( ) ; + + i ) {
2015-09-12 14:59:50 +03:00
if ( i . value ( ) > 0 ) continue ;
2015-04-04 23:01:34 +03:00
if ( i . key ( ) - > pendingTill < = t ) {
2016-09-27 16:37:18 +03:00
auto j = items . constFind ( i . key ( ) ) ;
2015-04-04 23:01:34 +03:00
if ( j ! = items . cend ( ) & & ! j . value ( ) . isEmpty ( ) ) {
2016-09-27 16:37:18 +03:00
for_const ( auto item , j . value ( ) ) {
2015-09-12 14:59:50 +03:00
if ( item - > id > 0 ) {
if ( item - > channelId ( ) = = NoChannel ) {
ids . push_back ( MTP_int ( item - > id ) ) ;
i . value ( ) = - 1 ;
} else {
2016-09-27 16:37:18 +03:00
auto channel = item - > history ( ) - > peer - > asChannel ( ) ;
2017-04-06 22:02:40 +03:00
auto channelMap = idsByChannel . find ( channel ) ;
2015-09-12 14:59:50 +03:00
if ( channelMap = = idsByChannel . cend ( ) ) {
2017-04-06 22:02:40 +03:00
channelMap = idsByChannel . insert ( channel , IndexAndMessageIds ( idsByChannel . size ( ) , QVector < MTPint > ( 1 , MTP_int ( item - > id ) ) ) ) ;
2015-09-12 14:59:50 +03:00
} else {
channelMap . value ( ) . second . push_back ( MTP_int ( item - > id ) ) ;
}
i . value ( ) = - channelMap . value ( ) . first - 2 ;
}
break ;
}
}
2015-04-04 23:01:34 +03:00
}
} else {
m = qMin ( m , i . key ( ) - > pendingTill - t ) ;
}
}
2015-09-12 14:59:50 +03:00
2017-04-06 22:02:40 +03:00
auto requestId = mtpRequestId ( 0 ) ;
if ( ! ids . isEmpty ( ) ) {
requestId = request ( MTPmessages_GetMessages ( MTP_vector < MTPint > ( ids ) ) ) . done ( [ this ] ( const MTPmessages_Messages & result , mtpRequestId requestId ) {
gotWebPages ( nullptr , result , requestId ) ;
} ) . after ( kSmallDelayMs ) . send ( ) ;
}
QVector < mtpRequestId > reqsByIndex ( idsByChannel . size ( ) , 0 ) ;
2016-09-27 16:37:18 +03:00
for ( auto i = idsByChannel . cbegin ( ) , e = idsByChannel . cend ( ) ; i ! = e ; + + i ) {
2017-04-06 22:02:40 +03:00
reqsByIndex [ i . value ( ) . first ] = request ( MTPchannels_GetMessages ( i . key ( ) - > inputChannel , MTP_vector < MTPint > ( i . value ( ) . second ) ) ) . done ( [ this , channel = i . key ( ) ] ( const MTPmessages_Messages & result , mtpRequestId requestId ) {
gotWebPages ( channel , result , requestId ) ;
} ) . after ( kSmallDelayMs ) . send ( ) ;
}
if ( requestId | | ! reqsByIndex . isEmpty ( ) ) {
for ( auto & pendingRequestId : _webPagesPending ) {
if ( pendingRequestId > 0 ) continue ;
if ( pendingRequestId < 0 ) {
if ( pendingRequestId = = - 1 ) {
pendingRequestId = requestId ;
2015-09-12 14:59:50 +03:00
} else {
2017-04-06 22:02:40 +03:00
pendingRequestId = reqsByIndex [ - pendingRequestId - 2 ] ;
2015-09-12 14:59:50 +03:00
}
2015-04-04 23:01:34 +03:00
}
}
}
2015-09-12 14:59:50 +03:00
2017-04-07 15:10:10 +03:00
if ( m < INT_MAX ) {
_webPagesTimer . callOnce ( m * 1000 ) ;
}
2015-04-04 23:01:34 +03:00
}
2017-04-06 19:49:42 +03:00
void ApiWrap : : requestParticipantsCountDelayed ( ChannelData * channel ) {
2017-04-07 15:10:10 +03:00
_participantsCountRequestTimer . call ( kReloadChannelMembersTimeout , [ this , channel ] {
2017-07-26 14:53:49 +03:00
channel - > updateFullForced ( ) ;
2017-04-06 19:49:42 +03:00
} ) ;
2015-11-13 18:14:33 +03:00
}
2015-09-13 11:41:27 +03:00
void ApiWrap : : gotWebPages ( ChannelData * channel , const MTPmessages_Messages & msgs , mtpRequestId req ) {
2015-04-04 23:01:34 +03:00
const QVector < MTPMessage > * v = 0 ;
switch ( msgs . type ( ) ) {
2015-09-04 16:01:31 +03:00
case mtpc_messages_messages : {
2016-09-27 16:37:18 +03:00
auto & d = msgs . c_messages_messages ( ) ;
2015-09-04 16:01:31 +03:00
App : : feedUsers ( d . vusers ) ;
App : : feedChats ( d . vchats ) ;
2017-03-10 22:46:28 +03:00
v = & d . vmessages . v ;
2015-09-04 16:01:31 +03:00
} break ;
case mtpc_messages_messagesSlice : {
2016-09-27 16:37:18 +03:00
auto & d = msgs . c_messages_messagesSlice ( ) ;
2015-09-04 16:01:31 +03:00
App : : feedUsers ( d . vusers ) ;
App : : feedChats ( d . vchats ) ;
2017-03-10 22:46:28 +03:00
v = & d . vmessages . v ;
2015-09-04 16:01:31 +03:00
} break ;
case mtpc_messages_channelMessages : {
2016-09-27 16:37:18 +03:00
auto & d = msgs . c_messages_channelMessages ( ) ;
2015-09-13 11:41:27 +03:00
if ( channel ) {
channel - > ptsReceived ( d . vpts . v ) ;
} else {
2015-09-19 12:13:21 +03:00
LOG ( ( " API Error: received messages.channelMessages when no channel was passed! (ApiWrap::gotWebPages) " ) ) ;
}
2015-09-04 16:01:31 +03:00
App : : feedUsers ( d . vusers ) ;
App : : feedChats ( d . vchats ) ;
2017-03-10 22:46:28 +03:00
v = & d . vmessages . v ;
2015-09-04 16:01:31 +03:00
} break ;
2017-11-20 23:54:05 +04:00
case mtpc_messages_messagesNotModified : {
LOG ( ( " API Error: received messages.messagesNotModified! (ApiWrap::gotWebPages) " ) ) ;
} break ;
2015-04-04 23:01:34 +03:00
}
2015-09-04 16:01:31 +03:00
if ( ! v ) return ;
QMap < uint64 , int32 > msgsIds ; // copied from feedMsgs
2015-04-04 23:01:34 +03:00
for ( int32 i = 0 , l = v - > size ( ) ; i < l ; + + i ) {
2016-04-08 14:44:35 +04:00
const auto & msg ( v - > at ( i ) ) ;
2015-04-04 23:01:34 +03:00
switch ( msg . type ( ) ) {
2015-09-04 16:01:31 +03:00
case mtpc_message : msgsIds . insert ( ( uint64 ( uint32 ( msg . c_message ( ) . vid . v ) ) < < 32 ) | uint64 ( i ) , i ) ; break ;
case mtpc_messageEmpty : msgsIds . insert ( ( uint64 ( uint32 ( msg . c_messageEmpty ( ) . vid . v ) ) < < 32 ) | uint64 ( i ) , i ) ; break ;
case mtpc_messageService : msgsIds . insert ( ( uint64 ( uint32 ( msg . c_messageService ( ) . vid . v ) ) < < 32 ) | uint64 ( i ) , i ) ; break ;
2015-04-04 23:01:34 +03:00
}
}
2016-09-27 16:37:18 +03:00
for_const ( auto msgId , msgsIds ) {
if ( auto item = App : : histories ( ) . addNewMessage ( v - > at ( msgId ) , NewMessageExisting ) ) {
2016-03-19 19:55:15 +03:00
item - > setPendingInitDimensions ( ) ;
2015-04-04 23:01:34 +03:00
}
}
2016-09-27 16:37:18 +03:00
auto & items = App : : webPageItems ( ) ;
for ( auto i = _webPagesPending . begin ( ) ; i ! = _webPagesPending . cend ( ) ; ) {
2015-04-04 23:01:34 +03:00
if ( i . value ( ) = = req ) {
if ( i . key ( ) - > pendingTill > 0 ) {
i . key ( ) - > pendingTill = - 1 ;
2016-09-27 16:37:18 +03:00
auto j = items . constFind ( i . key ( ) ) ;
2015-04-04 23:01:34 +03:00
if ( j ! = items . cend ( ) ) {
2016-09-27 16:37:18 +03:00
for_const ( auto item , j . value ( ) ) {
item - > setPendingInitDimensions ( ) ;
2015-04-04 23:01:34 +03:00
}
}
}
i = _webPagesPending . erase ( i ) ;
} else {
+ + i ;
}
}
}
2016-11-22 12:48:13 +03:00
void ApiWrap : : stickersSaveOrder ( ) {
if ( _stickersOrder . size ( ) > 1 ) {
QVector < MTPlong > mtpOrder ;
mtpOrder . reserve ( _stickersOrder . size ( ) ) ;
for_const ( auto setId , _stickersOrder ) {
mtpOrder . push_back ( MTP_long ( setId ) ) ;
}
2017-04-06 22:02:40 +03:00
_stickersReorderRequestId = request ( MTPmessages_ReorderStickerSets ( MTP_flags ( 0 ) , MTP_vector < MTPlong > ( mtpOrder ) ) ) . done ( [ this ] ( const MTPBool & result ) {
_stickersReorderRequestId = 0 ;
} ) . fail ( [ this ] ( const RPCError & error ) {
_stickersReorderRequestId = 0 ;
2017-11-05 21:07:27 +04:00
Auth ( ) . data ( ) . setLastStickersUpdate ( 0 ) ;
2017-08-02 18:07:28 +03:00
updateStickers ( ) ;
2017-04-06 22:02:40 +03:00
} ) . send ( ) ;
2016-11-22 12:48:13 +03:00
}
}
2017-08-02 18:07:28 +03:00
void ApiWrap : : updateStickers ( ) {
auto now = getms ( true ) ;
2017-08-02 22:57:49 +02:00
requestStickers ( now ) ;
requestRecentStickers ( now ) ;
requestFavedStickers ( now ) ;
requestFeaturedStickers ( now ) ;
requestSavedGifs ( now ) ;
2017-08-02 18:07:28 +03:00
}
2017-08-17 11:31:24 +03:00
void ApiWrap : : setGroupStickerSet ( not_null < ChannelData * > megagroup , const MTPInputStickerSet & set ) {
2017-08-05 12:48:21 +02:00
Expects ( megagroup - > mgInfo ! = nullptr ) ;
megagroup - > mgInfo - > stickerSet = set ;
request ( MTPchannels_SetStickers ( megagroup - > inputChannel , set ) ) . send ( ) ;
2017-11-05 21:07:27 +04:00
Auth ( ) . data ( ) . markStickersUpdated ( ) ;
2017-08-05 12:48:21 +02:00
}
2017-08-02 22:57:49 +02:00
void ApiWrap : : requestStickers ( TimeId now ) {
2017-11-05 21:07:27 +04:00
if ( ! Auth ( ) . data ( ) . stickersUpdateNeeded ( now )
| | _stickersUpdateRequest ) {
2017-08-02 22:57:49 +02:00
return ;
2017-08-02 18:07:28 +03:00
}
2017-08-02 22:57:49 +02:00
auto onDone = [ this ] ( const MTPmessages_AllStickers & result ) {
2017-11-05 21:07:27 +04:00
Auth ( ) . data ( ) . setLastStickersUpdate ( getms ( true ) ) ;
2017-08-02 22:57:49 +02:00
_stickersUpdateRequest = 0 ;
2017-08-02 18:07:28 +03:00
2017-08-02 22:57:49 +02:00
switch ( result . type ( ) ) {
case mtpc_messages_allStickersNotModified : return ;
case mtpc_messages_allStickers : {
auto & d = result . c_messages_allStickers ( ) ;
Stickers : : SetsReceived ( d . vsets . v , d . vhash . v ) ;
} return ;
default : Unexpected ( " Type in ApiWrap::stickersDone() " ) ;
2017-08-02 18:07:28 +03:00
}
2017-08-02 22:57:49 +02:00
} ;
_stickersUpdateRequest = request ( MTPmessages_GetAllStickers ( MTP_int ( Local : : countStickersHash ( true ) ) ) ) . done ( onDone ) . fail ( [ this , onDone ] ( const RPCError & error ) {
LOG ( ( " App Fail: Failed to get stickers! " ) ) ;
onDone ( MTP_messages_allStickersNotModified ( ) ) ;
} ) . send ( ) ;
2017-08-02 18:07:28 +03:00
}
2017-08-02 22:57:49 +02:00
void ApiWrap : : requestRecentStickers ( TimeId now ) {
2017-11-05 21:07:27 +04:00
if ( ! Auth ( ) . data ( ) . recentStickersUpdateNeeded ( now )
| | _recentStickersUpdateRequest ) {
2017-08-02 22:57:49 +02:00
return ;
2017-08-02 18:07:28 +03:00
}
2017-08-02 22:57:49 +02:00
auto onDone = [ this ] ( const MTPmessages_RecentStickers & result ) {
2017-11-05 21:07:27 +04:00
Auth ( ) . data ( ) . setLastRecentStickersUpdate ( getms ( true ) ) ;
2017-08-02 22:57:49 +02:00
_recentStickersUpdateRequest = 0 ;
2017-08-02 18:07:28 +03:00
2017-08-02 22:57:49 +02:00
switch ( result . type ( ) ) {
case mtpc_messages_recentStickersNotModified : return ;
case mtpc_messages_recentStickers : {
auto & d = result . c_messages_recentStickers ( ) ;
Stickers : : SpecialSetReceived ( Stickers : : CloudRecentSetId , lang ( lng_recent_stickers ) , d . vstickers . v , d . vhash . v ) ;
} return ;
default : Unexpected ( " Type in ApiWrap::recentStickersDone() " ) ;
2017-08-02 18:07:28 +03:00
}
2017-08-02 22:57:49 +02:00
} ;
_recentStickersUpdateRequest = request ( MTPmessages_GetRecentStickers ( MTP_flags ( 0 ) , MTP_int ( Local : : countRecentStickersHash ( ) ) ) ) . done ( onDone ) . fail ( [ this , onDone ] ( const RPCError & error ) {
LOG ( ( " App Fail: Failed to get recent stickers! " ) ) ;
onDone ( MTP_messages_recentStickersNotModified ( ) ) ;
} ) . send ( ) ;
2017-08-02 18:07:28 +03:00
}
2017-08-02 22:57:49 +02:00
void ApiWrap : : requestFavedStickers ( TimeId now ) {
2017-11-05 21:07:27 +04:00
if ( ! Auth ( ) . data ( ) . favedStickersUpdateNeeded ( now )
| | _favedStickersUpdateRequest ) {
2017-08-02 22:57:49 +02:00
return ;
2017-08-02 18:07:28 +03:00
}
2017-08-02 22:57:49 +02:00
auto onDone = [ this ] ( const MTPmessages_FavedStickers & result ) {
2017-11-05 21:07:27 +04:00
Auth ( ) . data ( ) . setLastFavedStickersUpdate ( getms ( true ) ) ;
2017-08-02 22:57:49 +02:00
_favedStickersUpdateRequest = 0 ;
2017-08-02 18:07:28 +03:00
2017-08-02 22:57:49 +02:00
switch ( result . type ( ) ) {
case mtpc_messages_favedStickersNotModified : return ;
case mtpc_messages_favedStickers : {
auto & d = result . c_messages_favedStickers ( ) ;
2017-09-28 23:11:10 +03:00
Stickers : : SpecialSetReceived ( Stickers : : FavedSetId , Lang : : Hard : : FavedSetTitle ( ) , d . vstickers . v , d . vhash . v , d . vpacks . v ) ;
2017-08-02 22:57:49 +02:00
} return ;
default : Unexpected ( " Type in ApiWrap::favedStickersDone() " ) ;
2017-08-02 18:07:28 +03:00
}
2017-08-02 22:57:49 +02:00
} ;
_favedStickersUpdateRequest = request ( MTPmessages_GetFavedStickers ( MTP_int ( Local : : countFavedStickersHash ( ) ) ) ) . done ( onDone ) . fail ( [ this , onDone ] ( const RPCError & error ) {
LOG ( ( " App Fail: Failed to get faved stickers! " ) ) ;
onDone ( MTP_messages_favedStickersNotModified ( ) ) ;
} ) . send ( ) ;
}
2017-08-02 18:07:28 +03:00
2017-08-02 22:57:49 +02:00
void ApiWrap : : requestFeaturedStickers ( TimeId now ) {
2017-11-05 21:07:27 +04:00
if ( ! Auth ( ) . data ( ) . featuredStickersUpdateNeeded ( now )
| | _featuredStickersUpdateRequest ) {
2017-08-02 22:57:49 +02:00
return ;
2017-08-02 18:07:28 +03:00
}
2017-08-02 22:57:49 +02:00
auto onDone = [ this ] ( const MTPmessages_FeaturedStickers & result ) {
2017-11-05 21:07:27 +04:00
Auth ( ) . data ( ) . setLastFeaturedStickersUpdate ( getms ( true ) ) ;
2017-08-02 22:57:49 +02:00
_featuredStickersUpdateRequest = 0 ;
2017-08-02 18:07:28 +03:00
2017-08-02 22:57:49 +02:00
switch ( result . type ( ) ) {
case mtpc_messages_featuredStickersNotModified : return ;
case mtpc_messages_featuredStickers : {
auto & d = result . c_messages_featuredStickers ( ) ;
Stickers : : FeaturedSetsReceived ( d . vsets . v , d . vunread . v , d . vhash . v ) ;
} return ;
default : Unexpected ( " Type in ApiWrap::featuredStickersDone() " ) ;
2017-08-02 18:07:28 +03:00
}
2017-08-02 22:57:49 +02:00
} ;
_featuredStickersUpdateRequest = request ( MTPmessages_GetFeaturedStickers ( MTP_int ( Local : : countFeaturedStickersHash ( ) ) ) ) . done ( onDone ) . fail ( [ this , onDone ] ( const RPCError & error ) {
LOG ( ( " App Fail: Failed to get featured stickers! " ) ) ;
onDone ( MTP_messages_featuredStickersNotModified ( ) ) ;
} ) . send ( ) ;
}
2017-08-02 18:07:28 +03:00
2017-08-02 22:57:49 +02:00
void ApiWrap : : requestSavedGifs ( TimeId now ) {
2017-11-05 21:07:27 +04:00
if ( ! Auth ( ) . data ( ) . savedGifsUpdateNeeded ( now )
| | _savedGifsUpdateRequest ) {
2017-08-02 22:57:49 +02:00
return ;
2017-08-02 18:07:28 +03:00
}
2017-08-02 22:57:49 +02:00
auto onDone = [ this ] ( const MTPmessages_SavedGifs & result ) {
2017-11-05 21:07:27 +04:00
Auth ( ) . data ( ) . setLastSavedGifsUpdate ( getms ( true ) ) ;
2017-08-02 22:57:49 +02:00
_savedGifsUpdateRequest = 0 ;
2017-08-02 18:07:28 +03:00
2017-08-02 22:57:49 +02:00
switch ( result . type ( ) ) {
case mtpc_messages_savedGifsNotModified : return ;
case mtpc_messages_savedGifs : {
auto & d = result . c_messages_savedGifs ( ) ;
Stickers : : GifsReceived ( d . vgifs . v , d . vhash . v ) ;
} return ;
default : Unexpected ( " Type in ApiWrap::savedGifsDone() " ) ;
}
} ;
_savedGifsUpdateRequest = request ( MTPmessages_GetSavedGifs ( MTP_int ( Local : : countSavedGifsHash ( ) ) ) ) . done ( onDone ) . fail ( [ this , onDone ] ( const RPCError & error ) {
LOG ( ( " App Fail: Failed to get saved gifs! " ) ) ;
onDone ( MTP_messages_savedGifsNotModified ( ) ) ;
} ) . send ( ) ;
2017-08-02 18:07:28 +03:00
}
2017-11-05 21:07:27 +04:00
void ApiWrap : : readFeaturedSetDelayed ( uint64 setId ) {
if ( ! _featuredSetsRead . contains ( setId ) ) {
_featuredSetsRead . insert ( setId ) ;
_featuredSetsReadTimer . callOnce ( kReadFeaturedSetsTimeout ) ;
}
}
void ApiWrap : : readFeaturedSets ( ) {
auto & sets = Auth ( ) . data ( ) . stickerSetsRef ( ) ;
auto count = Auth ( ) . data ( ) . featuredStickerSetsUnreadCount ( ) ;
QVector < MTPlong > wrappedIds ;
wrappedIds . reserve ( _featuredSetsRead . size ( ) ) ;
for ( auto setId : _featuredSetsRead ) {
auto it = sets . find ( setId ) ;
if ( it ! = sets . cend ( ) ) {
it - > flags & = ~ MTPDstickerSet_ClientFlag : : f_unread ;
wrappedIds . append ( MTP_long ( setId ) ) ;
if ( count ) {
- - count ;
}
}
}
_featuredSetsRead . clear ( ) ;
if ( ! wrappedIds . empty ( ) ) {
auto requestData = MTPmessages_ReadFeaturedStickers (
MTP_vector < MTPlong > ( wrappedIds ) ) ;
request ( std : : move ( requestData ) ) . done ( [ ] ( const MTPBool & result ) {
Local : : writeFeaturedStickers ( ) ;
Auth ( ) . data ( ) . markStickersUpdated ( ) ;
} ) . send ( ) ;
Auth ( ) . data ( ) . setFeaturedStickerSetsUnreadCount ( count ) ;
}
}
2017-11-20 23:54:05 +04:00
void ApiWrap : : parseChannelParticipants (
const MTPchannels_ChannelParticipants & result ,
base : : lambda < void ( int fullCount , const QVector < MTPChannelParticipant > & list ) > callbackList ,
base : : lambda < void ( ) > callbackNotModified ) {
2017-11-21 15:59:18 +04:00
TLHelp : : VisitChannelParticipants ( result , base : : overload ( [ & ] (
2017-11-20 23:54:05 +04:00
const MTPDchannels_channelParticipants & data ) {
App : : feedUsers ( data . vusers ) ;
if ( callbackList ) {
callbackList ( data . vcount . v , data . vparticipants . v ) ;
}
} , [ & ] ( mtpTypeId ) {
if ( callbackNotModified ) {
callbackNotModified ( ) ;
} else {
LOG ( ( " API Error: channels.channelParticipantsNotModified received! " ) ) ;
}
} ) ) ;
} ;
2017-07-14 14:54:47 +03:00
void ApiWrap : : applyUpdatesNoPtsCheck ( const MTPUpdates & updates ) {
switch ( updates . type ( ) ) {
case mtpc_updateShortMessage : {
auto & d = updates . c_updateShortMessage ( ) ;
auto flags = mtpCastFlags ( d . vflags . v ) | MTPDmessage : : Flag : : f_from_id ;
2017-08-04 16:54:32 +02:00
App : : histories ( ) . addNewMessage ( MTP_message ( MTP_flags ( flags ) , d . vid , d . is_out ( ) ? MTP_int ( Auth ( ) . userId ( ) ) : d . vuser_id , MTP_peerUser ( d . is_out ( ) ? d . vuser_id : MTP_int ( Auth ( ) . userId ( ) ) ) , d . vfwd_from , d . vvia_bot_id , d . vreply_to_msg_id , d . vdate , d . vmessage , MTP_messageMediaEmpty ( ) , MTPnullMarkup , d . has_entities ( ) ? d . ventities : MTPnullEntities , MTPint ( ) , MTPint ( ) , MTPstring ( ) ) , NewMessageUnread ) ;
2017-07-14 14:54:47 +03:00
} break ;
case mtpc_updateShortChatMessage : {
auto & d = updates . c_updateShortChatMessage ( ) ;
auto flags = mtpCastFlags ( d . vflags . v ) | MTPDmessage : : Flag : : f_from_id ;
2017-07-12 22:14:20 +03:00
App : : histories ( ) . addNewMessage ( MTP_message ( MTP_flags ( flags ) , d . vid , d . vfrom_id , MTP_peerChat ( d . vchat_id ) , d . vfwd_from , d . vvia_bot_id , d . vreply_to_msg_id , d . vdate , d . vmessage , MTP_messageMediaEmpty ( ) , MTPnullMarkup , d . has_entities ( ) ? d . ventities : MTPnullEntities , MTPint ( ) , MTPint ( ) , MTPstring ( ) ) , NewMessageUnread ) ;
2017-07-14 14:54:47 +03:00
} break ;
case mtpc_updateShortSentMessage : {
auto & d = updates . c_updateShortSentMessage ( ) ;
Q_UNUSED ( d ) ; // Sent message data was applied anyway.
} break ;
default : Unexpected ( " Type in applyUpdatesNoPtsCheck() " ) ;
}
}
void ApiWrap : : applyUpdateNoPtsCheck ( const MTPUpdate & update ) {
switch ( update . type ( ) ) {
case mtpc_updateNewMessage : {
auto & d = update . c_updateNewMessage ( ) ;
auto needToAdd = true ;
if ( d . vmessage . type ( ) = = mtpc_message ) { // index forwarded messages to links _overview
if ( App : : checkEntitiesAndViewsUpdate ( d . vmessage . c_message ( ) ) ) { // already in blocks
LOG ( ( " Skipping message, because it is already in blocks! " ) ) ;
needToAdd = false ;
}
}
if ( needToAdd ) {
App : : histories ( ) . addNewMessage ( d . vmessage , NewMessageUnread ) ;
}
} break ;
case mtpc_updateReadMessagesContents : {
auto & d = update . c_updateReadMessagesContents ( ) ;
2017-08-11 09:16:07 +02:00
auto possiblyReadMentions = base : : flat_set < MsgId > ( ) ;
for_const ( auto & msgId , d . vmessages . v ) {
if ( auto item = App : : histItemById ( NoChannel , msgId . v ) ) {
2017-07-14 14:54:47 +03:00
if ( item - > isMediaUnread ( ) ) {
item - > markMediaRead ( ) ;
2017-10-05 16:35:52 +01:00
Auth ( ) . data ( ) . requestItemRepaint ( item ) ;
2017-07-14 14:54:47 +03:00
if ( item - > out ( ) & & item - > history ( ) - > peer - > isUser ( ) ) {
auto when = App : : main ( ) - > requestingDifference ( ) ? 0 : unixtime ( ) ;
item - > history ( ) - > peer - > asUser ( ) - > madeAction ( when ) ;
}
}
2017-08-11 09:16:07 +02:00
} else {
// Perhaps it was an unread mention!
possiblyReadMentions . insert ( msgId . v ) ;
2017-07-14 14:54:47 +03:00
}
}
2017-08-11 09:16:07 +02:00
checkForUnreadMentions ( possiblyReadMentions ) ;
2017-07-14 14:54:47 +03:00
} break ;
case mtpc_updateReadHistoryInbox : {
auto & d = update . c_updateReadHistoryInbox ( ) ;
App : : feedInboxRead ( peerFromMTP ( d . vpeer ) , d . vmax_id . v ) ;
} break ;
case mtpc_updateReadHistoryOutbox : {
auto & d = update . c_updateReadHistoryOutbox ( ) ;
auto peerId = peerFromMTP ( d . vpeer ) ;
auto when = App : : main ( ) - > requestingDifference ( ) ? 0 : unixtime ( ) ;
App : : feedOutboxRead ( peerId , d . vmax_id . v , when ) ;
} break ;
case mtpc_updateWebPage : {
auto & d = update . c_updateWebPage ( ) ;
Q_UNUSED ( d ) ; // Web page was updated anyway.
} break ;
case mtpc_updateDeleteMessages : {
auto & d = update . c_updateDeleteMessages ( ) ;
App : : feedWereDeleted ( NoChannel , d . vmessages . v ) ;
} break ;
case mtpc_updateNewChannelMessage : {
auto & d = update . c_updateNewChannelMessage ( ) ;
auto needToAdd = true ;
if ( d . vmessage . type ( ) = = mtpc_message ) { // index forwarded messages to links _overview
if ( App : : checkEntitiesAndViewsUpdate ( d . vmessage . c_message ( ) ) ) { // already in blocks
LOG ( ( " Skipping message, because it is already in blocks! " ) ) ;
needToAdd = false ;
}
}
if ( needToAdd ) {
App : : histories ( ) . addNewMessage ( d . vmessage , NewMessageUnread ) ;
}
} break ;
case mtpc_updateEditChannelMessage : {
auto & d = update . c_updateEditChannelMessage ( ) ;
App : : updateEditedMessage ( d . vmessage ) ;
} break ;
case mtpc_updateEditMessage : {
auto & d = update . c_updateEditMessage ( ) ;
App : : updateEditedMessage ( d . vmessage ) ;
} break ;
case mtpc_updateChannelWebPage : {
auto & d = update . c_updateChannelWebPage ( ) ;
Q_UNUSED ( d ) ; // Web page was updated anyway.
} break ;
case mtpc_updateDeleteChannelMessages : {
auto & d = update . c_updateDeleteChannelMessages ( ) ;
App : : feedWereDeleted ( d . vchannel_id . v , d . vmessages . v ) ;
} break ;
default : Unexpected ( " Type in applyUpdateNoPtsCheck() " ) ;
}
}
2017-08-17 11:31:24 +03:00
void ApiWrap : : jumpToDate ( not_null < PeerData * > peer , const QDate & date ) {
2017-08-01 14:43:50 +03:00
// API returns a message with date <= offset_date.
// So we request a message with offset_date = desired_date - 1 and add_offset = -1.
// This should give us the first message with date >= desired_date.
2017-11-20 23:54:05 +04:00
auto offsetId = 0 ;
auto offsetDate = static_cast < int > ( QDateTime ( date ) . toTime_t ( ) ) - 1 ;
auto addOffset = - 1 ;
2017-08-01 14:43:50 +03:00
auto limit = 1 ;
2017-11-20 23:54:05 +04:00
auto maxId = 0 ;
auto minId = 0 ;
auto historyHash = 0 ;
request ( MTPmessages_GetHistory (
peer - > input ,
MTP_int ( offsetId ) ,
MTP_int ( offsetDate ) ,
MTP_int ( addOffset ) ,
MTP_int ( limit ) ,
MTP_int ( maxId ) ,
MTP_int ( minId ) ,
MTP_int ( historyHash )
) ) . done ( [ peer ] ( const MTPmessages_Messages & result ) {
2017-08-01 14:43:50 +03:00
auto getMessagesList = [ & result , peer ] ( ) - > const QVector < MTPMessage > * {
auto handleMessages = [ ] ( auto & messages ) {
App : : feedUsers ( messages . vusers ) ;
App : : feedChats ( messages . vchats ) ;
return & messages . vmessages . v ;
} ;
switch ( result . type ( ) ) {
2017-11-20 23:54:05 +04:00
case mtpc_messages_messages :
return handleMessages ( result . c_messages_messages ( ) ) ;
case mtpc_messages_messagesSlice :
return handleMessages ( result . c_messages_messagesSlice ( ) ) ;
2017-08-01 14:43:50 +03:00
case mtpc_messages_channelMessages : {
auto & messages = result . c_messages_channelMessages ( ) ;
if ( peer & & peer - > isChannel ( ) ) {
peer - > asChannel ( ) - > ptsReceived ( messages . vpts . v ) ;
} else {
2017-11-20 23:54:05 +04:00
LOG ( ( " API Error: received messages.channelMessages when no channel was passed! (ApiWrap::jumpToDate) " ) ) ;
2017-08-01 14:43:50 +03:00
}
return handleMessages ( messages ) ;
} break ;
2017-11-20 23:54:05 +04:00
case mtpc_messages_messagesNotModified : {
LOG ( ( " API Error: received messages.messagesNotModified! (ApiWrap::jumpToDate) " ) ) ;
} break ;
2017-08-01 14:43:50 +03:00
}
return nullptr ;
} ;
if ( auto list = getMessagesList ( ) ) {
App : : feedMsgs ( * list , NewMessageExisting ) ;
for ( auto & message : * list ) {
auto id = idFromMessage ( message ) ;
Ui : : showPeerHistory ( peer , id ) ;
return ;
}
}
Ui : : showPeerHistory ( peer , ShowAtUnreadMsgId ) ;
} ) . send ( ) ;
}
2017-08-17 11:31:24 +03:00
void ApiWrap : : preloadEnoughUnreadMentions ( not_null < History * > history ) {
2017-08-11 09:16:07 +02:00
auto fullCount = history - > getUnreadMentionsCount ( ) ;
auto loadedCount = history - > getUnreadMentionsLoadedCount ( ) ;
auto allLoaded = ( fullCount > = 0 ) ? ( loadedCount > = fullCount ) : false ;
if ( fullCount < 0 | | loadedCount > = kUnreadMentionsPreloadIfLess | | allLoaded ) {
return ;
}
if ( _unreadMentionsRequests . contains ( history ) ) {
return ;
}
auto offsetId = loadedCount ? history - > getMaxLoadedUnreadMention ( ) : 1 ;
auto limit = loadedCount ? kUnreadMentionsNextRequestLimit : kUnreadMentionsFirstRequestLimit ;
auto addOffset = loadedCount ? - ( limit + 1 ) : - limit ;
auto maxId = 0 ;
auto minId = 0 ;
auto requestId = request ( MTPmessages_GetUnreadMentions ( history - > peer - > input , MTP_int ( offsetId ) , MTP_int ( addOffset ) , MTP_int ( limit ) , MTP_int ( maxId ) , MTP_int ( minId ) ) ) . done ( [ this , history ] ( const MTPmessages_Messages & result ) {
_unreadMentionsRequests . remove ( history ) ;
history - > addUnreadMentionsSlice ( result ) ;
} ) . fail ( [ this , history ] ( const RPCError & error ) {
_unreadMentionsRequests . remove ( history ) ;
} ) . send ( ) ;
_unreadMentionsRequests . emplace ( history , requestId ) ;
}
void ApiWrap : : checkForUnreadMentions ( const base : : flat_set < MsgId > & possiblyReadMentions , ChannelData * channel ) {
for ( auto msgId : possiblyReadMentions ) {
requestMessageData ( channel , msgId , [ ] ( ChannelData * channel , MsgId msgId ) {
if ( auto item = App : : histItemById ( channel , msgId ) ) {
if ( item - > mentionsMe ( ) ) {
item - > markMediaRead ( ) ;
}
}
} ) ;
}
}
2017-08-17 11:31:24 +03:00
void ApiWrap : : cancelEditChatAdmins ( not_null < ChatData * > chat ) {
2017-11-20 16:23:20 +04:00
_chatAdminsEnabledRequests . take (
chat
) | requestCanceller ( ) ;
_chatAdminsSaveRequests . take (
chat
) | [ & ] ( auto & & requests ) {
ranges : : for_each ( std : : move ( requests ) , requestCanceller ( ) ) ;
} ;
2017-08-14 15:48:11 +03:00
_chatAdminsToSave . remove ( chat ) ;
}
void ApiWrap : : editChatAdmins (
2017-08-17 11:31:24 +03:00
not_null < ChatData * > chat ,
2017-08-14 15:48:11 +03:00
bool adminsEnabled ,
2017-08-17 11:31:24 +03:00
base : : flat_set < not_null < UserData * > > & & admins ) {
2017-08-14 15:48:11 +03:00
cancelEditChatAdmins ( chat ) ;
if ( adminsEnabled ) {
_chatAdminsToSave . emplace ( chat , std : : move ( admins ) ) ;
}
auto requestId = request ( MTPmessages_ToggleChatAdmins ( chat - > inputChat , MTP_bool ( adminsEnabled ) ) ) . done ( [ this , chat ] ( const MTPUpdates & updates ) {
_chatAdminsEnabledRequests . remove ( chat ) ;
applyUpdates ( updates ) ;
saveChatAdmins ( chat ) ;
} ) . fail ( [ this , chat ] ( const RPCError & error ) {
_chatAdminsEnabledRequests . remove ( chat ) ;
if ( error . type ( ) = = qstr ( " CHAT_NOT_MODIFIED " ) ) {
saveChatAdmins ( chat ) ;
}
} ) . send ( ) ;
_chatAdminsEnabledRequests . emplace ( chat , requestId ) ;
}
2017-08-17 11:31:24 +03:00
void ApiWrap : : saveChatAdmins ( not_null < ChatData * > chat ) {
2017-08-14 15:48:11 +03:00
if ( ! _chatAdminsToSave . contains ( chat ) ) {
return ;
}
auto requestId = request ( MTPmessages_GetFullChat ( chat - > inputChat ) ) . done ( [ this , chat ] ( const MTPmessages_ChatFull & result ) {
_chatAdminsEnabledRequests . remove ( chat ) ;
processFullPeer ( chat , result ) ;
sendSaveChatAdminsRequests ( chat ) ;
} ) . fail ( [ this , chat ] ( const RPCError & error ) {
_chatAdminsEnabledRequests . remove ( chat ) ;
_chatAdminsToSave . remove ( chat ) ;
} ) . send ( ) ;
_chatAdminsEnabledRequests . emplace ( chat , requestId ) ;
}
2017-08-17 11:31:24 +03:00
void ApiWrap : : sendSaveChatAdminsRequests ( not_null < ChatData * > chat ) {
auto editOne = [ this , chat ] ( not_null < UserData * > user , bool admin ) {
2017-08-14 15:48:11 +03:00
auto requestId = request ( MTPmessages_EditChatAdmin (
chat - > inputChat ,
user - > inputUser ,
MTP_bool ( admin ) ) )
. done ( [ this , chat , user , admin ] (
const MTPBool & result ,
mtpRequestId requestId ) {
_chatAdminsSaveRequests [ chat ] . remove ( requestId ) ;
if ( _chatAdminsSaveRequests [ chat ] . empty ( ) ) {
_chatAdminsSaveRequests . remove ( chat ) ;
Notify : : peerUpdatedDelayed ( chat , Notify : : PeerUpdate : : Flag : : AdminsChanged ) ;
}
if ( mtpIsTrue ( result ) ) {
if ( admin ) {
if ( chat - > noParticipantInfo ( ) ) {
requestFullPeer ( chat ) ;
} else {
chat - > admins . insert ( user ) ;
}
} else {
chat - > admins . remove ( user ) ;
}
}
} ) . fail ( [ this , chat ] (
const RPCError & error ,
mtpRequestId requestId ) {
_chatAdminsSaveRequests [ chat ] . remove ( requestId ) ;
if ( _chatAdminsSaveRequests [ chat ] . empty ( ) ) {
_chatAdminsSaveRequests . remove ( chat ) ;
}
chat - > invalidateParticipants ( ) ;
if ( error . type ( ) = = qstr ( " USER_RESTRICTED " ) ) {
Ui : : show ( Box < InformBox > ( lang ( lng_cant_do_this ) ) ) ;
}
} ) . canWait ( 5 ) . send ( ) ;
_chatAdminsSaveRequests [ chat ] . insert ( requestId ) ;
} ;
auto appointOne = [ & ] ( auto user ) { editOne ( user , true ) ; } ;
auto removeOne = [ & ] ( auto user ) { editOne ( user , false ) ; } ;
auto admins = _chatAdminsToSave . take ( chat ) ;
2017-08-17 12:06:26 +03:00
Assert ( ! ! admins ) ;
2017-08-14 15:48:11 +03:00
auto toRemove = chat - > admins ;
2017-08-17 11:31:24 +03:00
auto toAppoint = std : : vector < not_null < UserData * > > ( ) ;
2017-08-14 15:48:11 +03:00
if ( ! admins - > empty ( ) ) {
toAppoint . reserve ( admins - > size ( ) ) ;
for ( auto user : * admins ) {
if ( ! toRemove . remove ( user ) & & user - > id ! = peerFromUser ( chat - > creator ) ) {
toAppoint . push_back ( user ) ;
}
}
}
2017-11-20 16:23:20 +04:00
ranges : : for_each ( toRemove , removeOne ) ;
ranges : : for_each ( toAppoint , appointOne ) ;
2017-08-14 15:48:11 +03:00
requestSendDelayed ( ) ;
}
2017-10-29 19:32:01 +04:00
void ApiWrap : : requestSharedMediaCount (
not_null < PeerData * > peer ,
Storage : : SharedMediaType type ) {
requestSharedMedia ( peer , type , 0 , SliceType : : Before ) ;
}
2017-08-18 22:14:31 +03:00
void ApiWrap : : requestSharedMedia (
not_null < PeerData * > peer ,
SharedMediaType type ,
MsgId messageId ,
SliceType slice ) {
auto key = std : : make_tuple ( peer , type , messageId , slice ) ;
if ( _sharedMediaRequests . contains ( key ) ) {
return ;
}
2017-10-30 23:24:20 +04:00
auto prepared = Api : : PrepareSearchRequest (
peer ,
type ,
QString ( ) ,
messageId ,
slice ) ;
if ( prepared . vfilter . type ( ) = = mtpc_inputMessagesFilterEmpty ) {
2017-08-18 22:14:31 +03:00
return ;
}
2017-10-30 23:24:20 +04:00
auto requestId = request (
std : : move ( prepared )
) . done ( [ this , peer , type , messageId , slice ] (
const MTPmessages_Messages & result ) {
auto key = std : : make_tuple ( peer , type , messageId , slice ) ;
_sharedMediaRequests . remove ( key ) ;
2017-08-18 22:14:31 +03:00
sharedMediaDone ( peer , type , messageId , slice , result ) ;
} ) . fail ( [ this , key ] ( const RPCError & error ) {
_sharedMediaRequests . remove ( key ) ;
} ) . send ( ) ;
_sharedMediaRequests . emplace ( key , requestId ) ;
}
void ApiWrap : : sharedMediaDone (
not_null < PeerData * > peer ,
SharedMediaType type ,
MsgId messageId ,
SliceType slice ,
const MTPmessages_Messages & result ) {
2017-10-30 23:24:20 +04:00
auto parsed = Api : : ParseSearchResult (
peer ,
type ,
messageId ,
slice ,
result ) ;
2017-08-18 22:14:31 +03:00
Auth ( ) . storage ( ) . add ( Storage : : SharedMediaAddSlice (
peer - > id ,
type ,
2017-10-30 23:24:20 +04:00
std : : move ( parsed . messageIds ) ,
parsed . noSkipRange ,
parsed . fullCount
2017-08-18 22:14:31 +03:00
) ) ;
}
2017-08-29 22:52:52 +03:00
void ApiWrap : : requestUserPhotos (
not_null < UserData * > user ,
PhotoId afterId ) {
if ( _userPhotosRequests . contains ( user ) ) {
return ;
}
auto limit = kSharedMediaLimit ;
auto requestId = request ( MTPphotos_GetUserPhotos (
user - > inputUser ,
MTP_int ( 0 ) ,
MTP_long ( afterId ) ,
MTP_int ( limit )
) ) . done ( [ this , user , afterId ] ( const MTPphotos_Photos & result ) {
_userPhotosRequests . remove ( user ) ;
userPhotosDone ( user , afterId , result ) ;
} ) . fail ( [ this , user ] ( const RPCError & error ) {
_userPhotosRequests . remove ( user ) ;
} ) . send ( ) ;
_userPhotosRequests . emplace ( user , requestId ) ;
}
void ApiWrap : : userPhotosDone (
not_null < UserData * > user ,
PhotoId photoId ,
const MTPphotos_Photos & result ) {
auto fullCount = 0 ;
auto & photos = * [ & ] {
switch ( result . type ( ) ) {
case mtpc_photos_photos : {
auto & d = result . c_photos_photos ( ) ;
App : : feedUsers ( d . vusers ) ;
fullCount = d . vphotos . v . size ( ) ;
return & d . vphotos . v ;
} break ;
case mtpc_photos_photosSlice : {
auto & d = result . c_photos_photosSlice ( ) ;
App : : feedUsers ( d . vusers ) ;
fullCount = d . vcount . v ;
return & d . vphotos . v ;
} break ;
}
Unexpected ( " photos.Photos type in userPhotosDone() " ) ;
} ( ) ;
auto photoIds = std : : vector < PhotoId > ( ) ;
photoIds . reserve ( photos . size ( ) ) ;
for ( auto & photo : photos ) {
if ( auto photoData = App : : feedPhoto ( photo ) ) {
photoIds . push_back ( photoData - > id ) ;
}
}
Auth ( ) . storage ( ) . add ( Storage : : UserPhotosAddSlice (
user - > id ,
std : : move ( photoIds ) ,
fullCount
) ) ;
}
2017-04-06 22:02:40 +03:00
ApiWrap : : ~ ApiWrap ( ) = default ;