/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include #include "base/timer.h" #include "base/flat_map.h" #include "base/flat_set.h" #include "mtproto/sender.h" #include "chat_helpers/stickers.h" #include "data/data_messages.h" class TaskQueue; class AuthSession; struct MessageGroupId; struct SendingAlbum; enum class SendMediaType; struct FileLoadTo; class mtpFileLoader; namespace Data { struct UpdatedFileReferences; class WallPaper; } // namespace Data namespace InlineBots { class Result; } // namespace InlineBots namespace Storage { enum class SharedMediaType : signed char; struct PreparedList; } // namespace Storage namespace Dialogs { class Key; } // namespace Dialogs namespace Core { struct CloudPasswordState; } // namespace Core namespace Api { template inline int32 CountHash(IntRange &&range) { uint32 acc = 0; for (auto value : range) { acc += (acc * 20261) + uint32(value); } return int32(acc & 0x7FFFFFFF); } } // namespace Api class ApiWrap : public MTP::Sender, private base::Subscriber { public: struct Privacy { enum class Key { PhoneNumber, LastSeen, Calls, Invites, CallsPeer2Peer, Forwards, ProfilePhoto, }; enum class Option { Everyone, Contacts, Nobody, }; Option option = Option::Everyone; std::vector> always; std::vector> never; static MTPInputPrivacyKey Input(Key key); static std::optional KeyFromMTP(mtpTypeId type); }; struct BlockedUsersSlice { struct Item { UserData *user = nullptr; TimeId date = 0; bool operator==(const Item &other) const; bool operator!=(const Item &other) const; }; QVector list; int total = 0; bool operator==(const BlockedUsersSlice &other) const; bool operator!=(const BlockedUsersSlice &other) const; }; ApiWrap(not_null session); void applyUpdates(const MTPUpdates &updates, uint64 sentMessageRandomId = 0); void applyNotifySettings( MTPInputNotifyPeer peer, const MTPPeerNotifySettings &settings); void savePinnedOrder(Data::Folder *folder); void toggleHistoryArchived( not_null history, bool archived, Fn callback); //void ungroupAllFromFeed(not_null feed); // #feed using RequestMessageDataCallback = Fn; void requestMessageData( ChannelData *channel, MsgId msgId, RequestMessageDataCallback callback); QString exportDirectMessageLink(not_null item); void requestContacts(); void requestDialogs(Data::Folder *folder = nullptr); void requestPinnedDialogs(Data::Folder *folder = nullptr); void requestMoreBlockedByDateDialogs(); rpl::producer dialogsLoadMayBlockByDate() const; rpl::producer dialogsLoadBlockedByDate() const; void requestDialogEntry(not_null folder); void requestDialogEntry( not_null history, Fn callback = nullptr); void dialogEntryApplied(not_null history); //void applyFeedSources(const MTPDchannels_feedSources &data); // #feed //void setFeedChannels( // not_null feed, // const std::vector> &channels); void changeDialogUnreadMark(not_null history, bool unread); //void changeDialogUnreadMark(not_null feed, bool unread); // #feed void requestFakeChatListMessage(not_null history); void requestWallPaper( const QString &slug, Fn done, Fn fail); void requestFullPeer(not_null peer); void requestPeer(not_null peer); void requestPeers(const QList &peers); void requestLastParticipants(not_null channel); void requestBots(not_null channel); void requestAdmins(not_null channel); void requestParticipantsCountDelayed(not_null channel); void requestChannelRangeDifference(not_null history); using UpdatedFileReferences = Data::UpdatedFileReferences; using FileReferencesHandler = FnMut; void refreshFileReference( Data::FileOrigin origin, FileReferencesHandler &&handler); void refreshFileReference( Data::FileOrigin origin, not_null loader, int requestId, const QByteArray ¤t); void requestChangelog( const QString &sinceVersion, Fn callback); void refreshProxyPromotion(); void requestDeepLinkInfo( const QString &path, Fn callback); void requestTermsUpdate(); void acceptTerms(bytes::const_span termsId); void checkChatInvite( const QString &hash, FnMut done, FnMut fail); void importChatInvite(const QString &hash); void requestChannelMembersForAdd( not_null channel, Fn callback); void processFullPeer( not_null peer, const MTPmessages_ChatFull &result); void processFullPeer( not_null user, const MTPUserFull &result); void migrateChat( not_null chat, FnMut)> done, FnMut fail = nullptr); void markMediaRead(const base::flat_set> &items); void markMediaRead(not_null item); void requestSelfParticipant(not_null channel); void kickParticipant(not_null chat, not_null user); void kickParticipant( not_null channel, not_null user, const MTPChatBannedRights ¤tRights); void unblockParticipant( not_null channel, not_null user); void deleteAllFromUser( not_null channel, not_null from); void saveDefaultRestrictions( not_null peer, const MTPChatBannedRights &rights, Fn callback = nullptr); void requestWebPageDelayed(WebPageData *page); void clearWebPageRequest(WebPageData *page); void clearWebPageRequests(); void requestAttachedStickerSets(not_null photo); void scheduleStickerSetRequest(uint64 setId, uint64 access); void requestStickerSets(); void saveStickerSets( const Stickers::Order &localOrder, const Stickers::Order &localRemoved); void updateStickers(); void requestRecentStickersForce(); void setGroupStickerSet( not_null megagroup, const MTPInputStickerSet &set); std::vector> *stickersByEmoji( not_null emoji); void toggleFavedSticker( not_null document, Data::FileOrigin origin, bool faved); void toggleSavedGif( not_null document, Data::FileOrigin origin, bool saved); void joinChannel(not_null channel); void leaveChannel(not_null channel); void blockUser(not_null user); void unblockUser(not_null user); void exportInviteLink(not_null peer); void requestNotifySettings(const MTPInputNotifyPeer &peer); void updateNotifySettingsDelayed(not_null peer); void saveDraftToCloudDelayed(not_null history); void savePrivacy( const MTPInputPrivacyKey &key, QVector &&rules); void handlePrivacyChange( Privacy::Key key, const MTPVector &rules); static int OnlineTillFromStatus( const MTPUserStatus &status, int currentOnlineTill); void clearHistory(not_null peer, bool revoke); void deleteConversation(not_null peer, bool revoke); void deleteMessages( not_null peer, const QVector &ids, bool revoke); base::Observable &fullPeerUpdated() { return _fullPeerUpdated; } bool isQuitPrevent(); void applyUpdatesNoPtsCheck(const MTPUpdates &updates); void applyUpdateNoPtsCheck(const MTPUpdate &update); void jumpToDate(Dialogs::Key chat, const QDate &date); void preloadEnoughUnreadMentions(not_null history); void checkForUnreadMentions( const base::flat_set &possiblyReadMentions, ChannelData *channel = nullptr); using SliceType = Data::LoadDirection; void requestSharedMedia( not_null peer, Storage::SharedMediaType type, MsgId messageId, SliceType slice); void requestSharedMediaCount( not_null peer, Storage::SharedMediaType type); void requestUserPhotos( not_null user, PhotoId afterId); //void requestFeedChannels( // #feed // not_null feed); //void requestFeedMessages( // not_null feed, // Data::MessagePosition messageId, // SliceType slice); //void saveDefaultFeedId(FeedId id, bool isDefaultFeedId); void stickerSetInstalled(uint64 setId) { _stickerSetInstalled.fire_copy(setId); } auto stickerSetInstalled() const { return _stickerSetInstalled.events(); } void readFeaturedSetDelayed(uint64 setId); void parseChannelParticipants( not_null channel, const MTPchannels_ChannelParticipants &result, Fn &list)> callbackList, Fn callbackNotModified = nullptr); void parseRecentChannelParticipants( not_null channel, const MTPchannels_ChannelParticipants &result, Fn &list)> callbackList, Fn callbackNotModified = nullptr); void addChatParticipants( not_null peer, const std::vector> &users); struct SendOptions { SendOptions(not_null history); not_null history; MsgId replyTo = 0; WebPageId webPageId = 0; bool clearDraft = false; bool generateLocal = true; bool handleSupportSwitch = false; }; rpl::producer sendActions() const { return _sendActions.events(); } void sendAction(const SendOptions &options); void forwardMessages( HistoryItemsList &&items, const SendOptions &options, FnMut &&successCallback = nullptr); void shareContact( const QString &phone, const QString &firstName, const QString &lastName, const SendOptions &options); void shareContact(not_null user, const SendOptions &options); void readServerHistory(not_null history); void readServerHistoryForce(not_null history); //void readFeed( // #feed // not_null feed, // Data::MessagePosition position); void sendVoiceMessage( QByteArray result, VoiceWaveform waveform, int duration, const SendOptions &options); void sendFiles( Storage::PreparedList &&list, SendMediaType type, TextWithTags &&caption, std::shared_ptr album, const SendOptions &options); void sendFile( const QByteArray &fileContent, SendMediaType type, const SendOptions &options); void editMedia( Storage::PreparedList &&list, SendMediaType type, TextWithTags &&caption, const SendOptions &options, MsgId msgIdToEdit); void sendUploadedPhoto( FullMsgId localId, const MTPInputFile &file, bool silent); void sendUploadedDocument( FullMsgId localId, const MTPInputFile &file, const std::optional &thumb, bool silent); void editUploadedFile( FullMsgId localId, const MTPInputFile &file, const std::optional &thumb, bool silent, bool isDocument); void cancelLocalItem(not_null item); struct MessageToSend { MessageToSend(not_null history); not_null history; TextWithTags textWithTags; MsgId replyTo = 0; WebPageId webPageId = 0; bool clearDraft = true; bool handleSupportSwitch = false; }; void sendMessage(MessageToSend &&message); void sendBotStart(not_null bot, PeerData *chat = nullptr); void sendInlineResult( not_null bot, not_null data, const SendOptions &options); void sendExistingDocument( not_null document, Data::FileOrigin origin, TextWithEntities caption, const SendOptions &options); void requestSupportContact(FnMut callback); void uploadPeerPhoto(not_null peer, QImage &&image); void clearPeerPhoto(not_null photo); void reloadPasswordState(); void clearUnconfirmedPassword(); rpl::producer passwordState() const; std::optional passwordStateCurrent() const; void reloadContactSignupSilent(); rpl::producer contactSignupSilent() const; std::optional contactSignupSilentCurrent() const; void saveContactSignupSilent(bool silent); void saveSelfBio(const QString &text, FnMut done); void reloadPrivacy(Privacy::Key key); rpl::producer privacyValue(Privacy::Key key); void reloadBlockedUsers(); rpl::producer blockedUsersSlice(); void reloadSelfDestruct(); rpl::producer selfDestructValue() const; void saveSelfDestruct(int days); void createPoll( const PollData &data, const SendOptions &options, FnMut done, FnMut fail); void sendPollVotes( FullMsgId itemId, const std::vector &options); void closePoll(not_null item); void reloadPollResults(not_null item); ~ApiWrap(); private: struct MessageDataRequest { using Callbacks = QList; mtpRequestId requestId = 0; Callbacks callbacks; }; using MessageDataRequests = QMap; using SharedMediaType = Storage::SharedMediaType; struct StickersByEmoji { std::vector> list; int32 hash = 0; crl::time received = 0; }; struct DialogsLoadState { TimeId offsetDate = 0; MsgId offsetId = 0; PeerData *offsetPeer = nullptr; mtpRequestId requestId = 0; bool listReceived = false; mtpRequestId pinnedRequestId = 0; bool pinnedReceived = false; }; void setupSupportMode(); void refreshDialogsLoadBlocked(); void updateDialogsOffset( Data::Folder *folder, const QVector &dialogs, const QVector &messages); void requestMoreDialogs(Data::Folder *folder); DialogsLoadState *dialogsLoadState(Data::Folder *folder); void dialogsLoadFinish(Data::Folder *folder); void checkQuitPreventFinished(); void saveDraftsToCloud(); void resolveMessageDatas(); void gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId requestId); void finalizeMessageDataRequest( ChannelData *channel, mtpRequestId requestId); QVector collectMessageIds(const MessageDataRequests &requests); MessageDataRequests *messageDataRequests(ChannelData *channel, bool onlyExisting = false); void applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs); void gotChatFull( not_null peer, const MTPmessages_ChatFull &result, mtpRequestId req); void gotUserFull( not_null user, const MTPUserFull &result, mtpRequestId req); void applyLastParticipantsList( not_null channel, int availableCount, const QVector &list); void applyBotsList( not_null channel, int availableCount, const QVector &list); void applyAdminsList( not_null channel, int availableCount, const QVector &list); void resolveWebPages(); void gotWebPages( ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req); void gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result); void channelRangeDifferenceSend( not_null channel, MsgRange range, int32 pts); void channelRangeDifferenceDone( not_null channel, MsgRange range, const MTPupdates_ChannelDifference &result); void stickerSetDisenabled(mtpRequestId requestId); void stickersSaveOrder(); void requestStickers(TimeId now); void requestRecentStickers(TimeId now); void requestRecentStickersWithHash(int32 hash); void requestFavedStickers(TimeId now); void requestFeaturedStickers(TimeId now); void requestSavedGifs(TimeId now); void readFeaturedSets(); void refreshChannelAdmins( not_null channel, const QVector &participants); void jumpToHistoryDate(not_null peer, const QDate &date); //void jumpToFeedDate(not_null feed, const QDate &date); // #feed template void requestMessageAfterDate( not_null peer, const QDate &date, Callback &&callback); //template // #feed //void requestMessageAfterDate( // not_null feed, // const QDate &date, // Callback &&callback); void sharedMediaDone( not_null peer, SharedMediaType type, MsgId messageId, SliceType slice, const MTPmessages_Messages &result); void userPhotosDone( not_null user, PhotoId photoId, const MTPphotos_Photos &result); //void feedChannelsDone(not_null feed); // #feed //void feedMessagesDone( // not_null feed, // Data::MessagePosition messageId, // SliceType slice, // const MTPmessages_FeedMessages &result); void sendSharedContact( const QString &phone, const QString &firstName, const QString &lastName, UserId userId, const SendOptions &options); void deleteHistory( not_null peer, bool justClear, bool revoke); void sendReadRequest(not_null peer, MsgId upTo); int applyAffectedHistory( not_null peer, const MTPmessages_AffectedHistory &result); void applyAffectedMessages(const MTPmessages_AffectedMessages &result); void applyAffectedMessages( not_null peer, const MTPmessages_AffectedMessages &result); void deleteAllFromUserSend( not_null channel, not_null from); void sendMessageFail(const RPCError &error); void uploadAlbumMedia( not_null item, const MessageGroupId &groupId, const MTPInputMedia &media); void sendAlbumWithUploaded( not_null item, const MessageGroupId &groupId, const MTPInputMedia &media); void sendAlbumWithCancelled( not_null item, const MessageGroupId &groupId); void sendAlbumIfReady(not_null album); void sendMedia( not_null item, const MTPInputMedia &media, bool silent); void sendMediaWithRandomId( not_null item, const MTPInputMedia &media, bool silent, uint64 randomId); FileLoadTo fileLoadTaskOptions(const SendOptions &options) const; //void readFeeds(); // #feed void getProxyPromotionDelayed(TimeId now, TimeId next); void proxyPromotionDone(const MTPhelp_ProxyData &proxy); void sendNotifySettingsUpdates(); template void requestFileReference( Data::FileOrigin origin, FileReferencesHandler &&handler, Request &&data); void photoUploadReady(const FullMsgId &msgId, const MTPInputFile &file); Privacy parsePrivacy(const QVector &rules); void pushPrivacy( Privacy::Key key, const QVector &rules); void updatePrivacyLastSeens(const QVector &rules); void setSelfDestructDays(int days); void migrateDone( not_null peer, not_null channel); void migrateFail(not_null peer, const RPCError &error); void sendDialogRequests(); not_null _session; MessageDataRequests _messageDataRequests; QMap _channelMessageDataRequests; SingleQueuedInvokation _messageDataResolveDelayed; using PeerRequests = QMap; PeerRequests _fullPeerRequests; PeerRequests _peerRequests; PeerRequests _participantsRequests; PeerRequests _botsRequests; PeerRequests _adminsRequests; base::DelayedCallTimer _participantsCountRequestTimer; ChannelData *_channelMembersForAdd = nullptr; mtpRequestId _channelMembersForAddRequestId = 0; Fn _channelMembersForAddCallback; base::flat_map< not_null, std::pair>> _historyArchivedRequests; using KickRequest = std::pair< not_null, not_null>; base::flat_map _kickRequests; base::flat_map< not_null, mtpRequestId> _defaultRestrictionsRequests; base::flat_set> _selfParticipantRequests; base::flat_map< not_null, mtpRequestId> _rangeDifferenceRequests; QMap _webPagesPending; base::Timer _webPagesTimer; QMap > _stickerSetRequests; QMap _channelAmInRequests; base::flat_map, mtpRequestId> _blockRequests; base::flat_map, mtpRequestId> _exportInviteRequests; base::flat_map _notifySettingRequests; base::flat_map, mtpRequestId> _draftsSaveRequestIds; base::Timer _draftsSaveTimer; base::flat_set _stickerSetDisenableRequests; Stickers::Order _stickersOrder; mtpRequestId _stickersReorderRequestId = 0; mtpRequestId _stickersClearRecentRequestId = 0; mtpRequestId _stickersUpdateRequest = 0; mtpRequestId _recentStickersUpdateRequest = 0; mtpRequestId _favedStickersUpdateRequest = 0; mtpRequestId _featuredStickersUpdateRequest = 0; mtpRequestId _savedGifsUpdateRequest = 0; base::Timer _featuredSetsReadTimer; base::flat_set _featuredSetsRead; base::flat_map, StickersByEmoji> _stickersByEmoji; base::flat_map _privacySaveRequests; mtpRequestId _contactsRequestId = 0; mtpRequestId _contactsStatusesRequestId = 0; base::flat_set> _dialogFolderRequests; base::flat_map< not_null, std::vector>> _dialogRequests; base::flat_map< not_null, std::vector>> _dialogRequestsPending; base::flat_set> _fakeChatListRequests; base::flat_map, mtpRequestId> _unreadMentionsRequests; base::flat_map, SharedMediaType, MsgId, SliceType>, mtpRequestId> _sharedMediaRequests; base::flat_map, mtpRequestId> _userPhotosRequests; //base::flat_set> _feedChannelsGetRequests; // #feed //base::flat_map< // not_null, // mtpRequestId> _feedChannelsSetRequests; //base::flat_set, // Data::MessagePosition, // SliceType>> _feedMessagesRequests; //base::flat_set, // Data::MessagePosition, // SliceType>> _feedMessagesRequestsPending; //mtpRequestId _saveDefaultFeedIdRequest = 0; std::unique_ptr _dialogsLoadState; TimeId _dialogsLoadTill = 0; rpl::variable _dialogsLoadMayBlockByDate = false; rpl::variable _dialogsLoadBlockedByDate = false; base::flat_map< not_null, DialogsLoadState> _foldersLoadState; rpl::event_stream _sendActions; struct ReadRequest { ReadRequest(mtpRequestId requestId, MsgId upTo) : requestId(requestId) , upTo(upTo) { } mtpRequestId requestId = 0; MsgId upTo = 0; }; base::flat_map, ReadRequest> _readRequests; base::flat_map, MsgId> _readRequestsPending; std::unique_ptr _fileLoader; base::flat_map> _sendingAlbums; base::Observable _fullPeerUpdated; rpl::event_stream _stickerSetInstalled; // #feed //base::flat_map, crl::time> _feedReadsDelayed; //base::flat_map, mtpRequestId> _feedReadRequests; //base::Timer _feedReadTimer; mtpRequestId _proxyPromotionRequestId = 0; std::pair _proxyPromotionKey; TimeId _proxyPromotionNextRequestTime = TimeId(0); base::Timer _proxyPromotionTimer; base::flat_set> _updateNotifySettingsPeers; base::Timer _updateNotifySettingsTimer; std::map< Data::FileOrigin, std::vector> _fileReferenceHandlers; mtpRequestId _deepLinkInfoRequestId = 0; crl::time _termsUpdateSendAt = 0; mtpRequestId _termsUpdateRequestId = 0; mtpRequestId _checkInviteRequestId = 0; FnMut _checkInviteDone; FnMut _checkInviteFail; struct MigrateCallbacks { FnMut)> done; FnMut fail; }; base::flat_map< not_null, std::vector> _migrateCallbacks; std::vector> _supportContactCallbacks; base::flat_map> _peerPhotoUploads; mtpRequestId _passwordRequestId = 0; std::unique_ptr _passwordState; rpl::event_stream _passwordStateChanges; mtpRequestId _saveBioRequestId = 0; FnMut _saveBioDone; QString _saveBioText; base::flat_map _privacyRequestIds; base::flat_map _privacyValues; std::map> _privacyChanges; mtpRequestId _blockedUsersRequestId = 0; std::optional _blockedUsersSlice; rpl::event_stream _blockedUsersChanges; mtpRequestId _selfDestructRequestId = 0; std::optional _selfDestructDays; rpl::event_stream _selfDestructChanges; base::flat_map _pollVotesRequestIds; base::flat_map _pollCloseRequestIds; base::flat_map _pollReloadRequestIds; mtpRequestId _wallPaperRequestId = 0; QString _wallPaperSlug; Fn _wallPaperDone; Fn _wallPaperFail; mtpRequestId _contactSignupSilentRequestId = 0; std::optional _contactSignupSilent; rpl::event_stream _contactSignupSilentChanges; mtpRequestId _attachedStickerSetsRequestId = 0; base::flat_map _unlikelyMessageLinks; };