/* 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 "api/api_common.h" #include "base/timer.h" #include "base/flat_map.h" #include "base/flat_set.h" #include "mtproto/sender.h" #include "data/stickers/data_stickers_set.h" #include "data/data_messages.h" class TaskQueue; struct MessageGroupId; struct SendingAlbum; enum class SendMediaType; struct FileLoadTo; struct ChatRestrictionsInfo; namespace Main { class Session; } // namespace Main namespace Data { struct UpdatedFileReferences; class WallPaper; struct ResolvedForwardDraft; enum class DefaultNotify; enum class StickersType : uchar; class Forum; class ForumTopic; class Thread; class Story; } // namespace Data namespace InlineBots { class Result; } // namespace InlineBots namespace Storage { enum class SharedMediaType : signed char; class DownloadMtprotoTask; class Account; } // namespace Storage namespace Dialogs { class Key; } // namespace Dialogs namespace Ui { struct PreparedList; } // namespace Ui namespace Api { struct SearchResult; class Updates; class Authorizations; class AttachedStickers; class BlockedPeers; class CloudPassword; class SelfDestruct; class SensitiveContent; class GlobalPrivacy; class UserPrivacy; class InviteLinks; class ViewsManager; class ConfirmPhone; class PeerPhoto; class Polls; class ChatParticipants; class UnreadThings; class Ringtones; class Transcribes; class Premium; class Usernames; namespace details { inline QString ToString(const QString &value) { return value; } inline QString ToString(int32 value) { return QString::number(value); } inline QString ToString(uint64 value) { return QString::number(value); } template inline QString ToString(ChatIdType value) { return QString::number(value.bare); } inline QString ToString(PeerId value) { return QString::number(value.value); } } // namespace details template < typename ...Types, typename = std::enable_if_t<(sizeof...(Types) > 0)>> QString RequestKey(Types &&...values) { const auto strings = { details::ToString(values)... }; if (strings.size() == 1) { return *strings.begin(); } auto result = QString(); result.reserve( ranges::accumulate(strings, 0, ranges::plus(), &QString::size)); for (const auto &string : strings) { result.append(string); } return result; } } // namespace Api class ApiWrap final : public MTP::Sender { public: using SendAction = Api::SendAction; using MessageToSend = Api::MessageToSend; explicit ApiWrap(not_null session); ~ApiWrap(); [[nodiscard]] Main::Session &session() const; [[nodiscard]] Storage::Account &local() const; [[nodiscard]] Api::Updates &updates() const; void applyUpdates( const MTPUpdates &updates, uint64 sentMessageRandomId = 0); int applyAffectedHistory( PeerData *peer, // May be nullptr, like for deletePhoneCallHistory. const MTPmessages_AffectedHistory &result); void registerModifyRequest(const QString &key, mtpRequestId requestId); void clearModifyRequest(const QString &key); void saveCurrentDraftToCloud(); void savePinnedOrder(Data::Folder *folder); void savePinnedOrder(not_null forum); void toggleHistoryArchived( not_null history, bool archived, Fn callback); void requestMessageData(PeerData *peer, MsgId msgId, Fn done); QString exportDirectMessageLink( not_null item, bool inRepliesContext); QString exportDirectStoryLink(not_null item); void requestContacts(); void requestDialogs(Data::Folder *folder = nullptr); void requestPinnedDialogs(Data::Folder *folder = nullptr); void requestMoreBlockedByDateDialogs(); void requestMoreDialogsIfNeeded(); rpl::producer dialogsLoadMayBlockByDate() const; rpl::producer dialogsLoadBlockedByDate() const; void requestWallPaper( const QString &slug, Fn done, Fn fail); void requestFullPeer(not_null peer); void requestPeerSettings(not_null peer); using UpdatedFileReferences = Data::UpdatedFileReferences; using FileReferencesHandler = FnMut; void refreshFileReference( Data::FileOrigin origin, FileReferencesHandler &&handler); void refreshFileReference( Data::FileOrigin origin, not_null task, int requestId, const QByteArray ¤t); void requestChangelog( const QString &sinceVersion, Fn callback); void refreshTopPromotion(); void requestDeepLinkInfo( const QString &path, Fn callback); void requestTermsUpdate(); void acceptTerms(bytes::const_span termsId); void checkChatInvite( const QString &hash, FnMut done, Fn fail); void checkFilterInvite( const QString &slug, FnMut done, Fn fail); void processFullPeer( not_null peer, const MTPmessages_ChatFull &result); void migrateChat( not_null chat, FnMut)> done, Fn fail = nullptr); void markContentsRead( const base::flat_set> &items); void markContentsRead(not_null item); void deleteAllFromParticipant( not_null channel, not_null from); void requestWebPageDelayed(not_null page); void clearWebPageRequest(not_null page); void clearWebPageRequests(); void scheduleStickerSetRequest(uint64 setId, uint64 access); void requestStickerSets(); void saveStickerSets( const Data::StickersSetsOrder &localOrder, const Data::StickersSetsOrder &localRemoved, Data::StickersType type); void updateStickers(); void updateSavedGifs(); void updateMasks(); void updateCustomEmoji(); void requestRecentStickersForce(bool attached = false); void setGroupStickerSet( not_null megagroup, const StickerSetIdentifier &set); [[nodiscard]] std::vector> *stickersByEmoji( const QString &key); void joinChannel(not_null channel); void leaveChannel(not_null channel); void requestNotifySettings(const MTPInputNotifyPeer &peer); void updateNotifySettingsDelayed(not_null thread); void updateNotifySettingsDelayed(not_null peer); void updateNotifySettingsDelayed(Data::DefaultNotify type); void saveDraftToCloudDelayed(not_null thread); static int OnlineTillFromStatus( const MTPUserStatus &status, int currentOnlineTill); void clearHistory(not_null peer, bool revoke); void deleteConversation(not_null peer, bool revoke); bool isQuitPrevent(); void resolveJumpToDate( Dialogs::Key chat, const QDate &date, Fn, MsgId)> callback); using SliceType = Data::LoadDirection; void requestSharedMedia( not_null peer, MsgId topicRootId, Storage::SharedMediaType type, MsgId messageId, SliceType slice); void readFeaturedSetDelayed(uint64 setId); rpl::producer sendActions() const { return _sendActions.events(); } void sendAction(const SendAction &action); void finishForwarding(const SendAction &action); void forwardMessages( Data::ResolvedForwardDraft &&draft, const SendAction &action, FnMut &&successCallback = nullptr); void shareContact( const QString &phone, const QString &firstName, const QString &lastName, const SendAction &action); void shareContact(not_null user, const SendAction &action); void applyAffectedMessages( not_null peer, const MTPmessages_AffectedMessages &result); void sendVoiceMessage( QByteArray result, VoiceWaveform waveform, int duration, const SendAction &action); void sendFiles( Ui::PreparedList &&list, SendMediaType type, TextWithTags &&caption, std::shared_ptr album, const SendAction &action); void sendFile( const QByteArray &fileContent, SendMediaType type, const SendAction &action); void editMedia( Ui::PreparedList &&list, SendMediaType type, TextWithTags &&caption, const SendAction &action); void sendUploadedPhoto( FullMsgId localId, Api::RemoteFileInfo info, Api::SendOptions options); void sendUploadedDocument( FullMsgId localId, Api::RemoteFileInfo file, Api::SendOptions options); void cancelLocalItem(not_null item); void sendMessage(MessageToSend &&message); void sendBotStart( not_null bot, PeerData *chat = nullptr, const QString &startTokenForChat = QString()); void sendInlineResult( not_null bot, not_null data, const SendAction &action, std::optional localMessageId); void sendMessageFail( const MTP::Error &error, not_null peer, uint64 randomId = 0, FullMsgId itemId = FullMsgId()); void sendMessageFail( const QString &error, not_null peer, uint64 randomId = 0, FullMsgId itemId = FullMsgId()); void reloadContactSignupSilent(); rpl::producer contactSignupSilent() const; std::optional contactSignupSilentCurrent() const; void saveContactSignupSilent(bool silent); [[nodiscard]] auto botCommonGroups(not_null bot) const -> std::optional>>; void requestBotCommonGroups(not_null bot, Fn done); void saveSelfBio(const QString &text); [[nodiscard]] Api::Authorizations &authorizations(); [[nodiscard]] Api::AttachedStickers &attachedStickers(); [[nodiscard]] Api::BlockedPeers &blockedPeers(); [[nodiscard]] Api::CloudPassword &cloudPassword(); [[nodiscard]] Api::SelfDestruct &selfDestruct(); [[nodiscard]] Api::SensitiveContent &sensitiveContent(); [[nodiscard]] Api::GlobalPrivacy &globalPrivacy(); [[nodiscard]] Api::UserPrivacy &userPrivacy(); [[nodiscard]] Api::InviteLinks &inviteLinks(); [[nodiscard]] Api::ViewsManager &views(); [[nodiscard]] Api::ConfirmPhone &confirmPhone(); [[nodiscard]] Api::PeerPhoto &peerPhoto(); [[nodiscard]] Api::Polls &polls(); [[nodiscard]] Api::ChatParticipants &chatParticipants(); [[nodiscard]] Api::UnreadThings &unreadThings(); [[nodiscard]] Api::Ringtones &ringtones(); [[nodiscard]] Api::Transcribes &transcribes(); [[nodiscard]] Api::Premium &premium(); [[nodiscard]] Api::Usernames &usernames(); void updatePrivacyLastSeens(); static constexpr auto kJoinErrorDuration = 5 * crl::time(1000); private: struct MessageDataRequest { using Callbacks = std::vector>; mtpRequestId requestId = 0; Callbacks callbacks; }; using MessageDataRequests = base::flat_map; using SharedMediaType = Storage::SharedMediaType; struct StickersByEmoji { std::vector> list; uint64 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 finalizeMessageDataRequest( ChannelData *channel, mtpRequestId requestId); [[nodiscard]] QVector collectMessageIds( const MessageDataRequests &requests); [[nodiscard]] MessageDataRequests *messageDataRequests( ChannelData *channel, bool onlyExisting = false); void gotChatFull( not_null peer, const MTPmessages_ChatFull &result); void gotUserFull( not_null user, const MTPusers_UserFull &result); void resolveWebPages(); void gotWebPages( ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req); void gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result); void requestStickers(TimeId now); void requestMasks(TimeId now); void requestCustomEmoji(TimeId now); void requestRecentStickers(TimeId now, bool attached = false); void requestRecentStickersWithHash(uint64 hash, bool attached = false); void requestFavedStickers(TimeId now); void requestFeaturedStickers(TimeId now); void requestFeaturedEmoji(TimeId now); void requestSavedGifs(TimeId now); void readFeaturedSets(); void resolveJumpToHistoryDate( not_null peer, MsgId topicRootId, const QDate &date, Fn, MsgId)> callback); template void requestMessageAfterDate( not_null peer, MsgId topicRootId, const QDate &date, Callback &&callback); void sharedMediaDone( not_null peer, MsgId topicRootId, SharedMediaType type, Api::SearchResult &&parsed); void sendSharedContact( const QString &phone, const QString &firstName, const QString &lastName, UserId userId, const SendAction &action); void deleteHistory( not_null peer, bool justClear, bool revoke); void applyAffectedMessages(const MTPmessages_AffectedMessages &result); void deleteAllFromParticipantSend( not_null channel, not_null from); 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, Api::SendOptions options); void sendMediaWithRandomId( not_null item, const MTPInputMedia &media, Api::SendOptions options, uint64 randomId); FileLoadTo fileLoadTaskOptions(const SendAction &action) const; void getTopPromotionDelayed(TimeId now, TimeId next); void topPromotionDone(const MTPhelp_PromoData &proxy); void sendNotifySettingsUpdates(); template void requestFileReference( Data::FileOrigin origin, FileReferencesHandler &&handler, Request &&data); void migrateDone( not_null peer, not_null channel); void migrateFail(not_null peer, const QString &error); const not_null _session; base::flat_map _modifyRequests; MessageDataRequests _messageDataRequests; base::flat_map< not_null, MessageDataRequests> _channelMessageDataRequests; SingleQueuedInvokation _messageDataResolveDelayed; using PeerRequests = base::flat_map; PeerRequests _fullPeerRequests; base::flat_set> _requestedPeerSettings; base::flat_map< not_null, std::pair>> _historyArchivedRequests; base::flat_map, mtpRequestId> _webPagesPending; base::Timer _webPagesTimer; struct StickerSetRequest { uint64 accessHash = 0; mtpRequestId id = 0; }; base::flat_map _stickerSetRequests; base::flat_map< not_null, mtpRequestId> _channelAmInRequests; struct NotifySettingsKey { PeerId peerId = 0; MsgId topicRootId = 0; friend inline constexpr auto operator<=>( NotifySettingsKey, NotifySettingsKey) = default; }; base::flat_map _notifySettingRequests; base::flat_map< base::weak_ptr, mtpRequestId> _draftsSaveRequestIds; base::Timer _draftsSaveTimer; base::flat_set _stickerSetDisenableRequests; base::flat_set _maskSetDisenableRequests; base::flat_set _customEmojiSetDisenableRequests; mtpRequestId _masksReorderRequestId = 0; mtpRequestId _customEmojiReorderRequestId = 0; mtpRequestId _stickersReorderRequestId = 0; mtpRequestId _stickersClearRecentRequestId = 0; mtpRequestId _stickersClearRecentAttachedRequestId = 0; mtpRequestId _stickersUpdateRequest = 0; mtpRequestId _masksUpdateRequest = 0; mtpRequestId _customEmojiUpdateRequest = 0; mtpRequestId _recentStickersUpdateRequest = 0; mtpRequestId _recentAttachedStickersUpdateRequest = 0; mtpRequestId _favedStickersUpdateRequest = 0; mtpRequestId _featuredStickersUpdateRequest = 0; mtpRequestId _featuredEmojiUpdateRequest = 0; mtpRequestId _savedGifsUpdateRequest = 0; base::Timer _featuredSetsReadTimer; base::flat_set _featuredSetsRead; base::flat_map _stickersByEmoji; mtpRequestId _contactsRequestId = 0; mtpRequestId _contactsStatusesRequestId = 0; struct SharedMediaRequest { not_null peer; MsgId topicRootId = 0; SharedMediaType mediaType = {}; MsgId aroundId = 0; SliceType sliceType = {}; friend inline auto operator<=>( const SharedMediaRequest&, const SharedMediaRequest&) = default; }; base::flat_set _sharedMediaRequests; 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; std::unique_ptr _fileLoader; base::flat_map> _sendingAlbums; mtpRequestId _topPromotionRequestId = 0; std::pair _topPromotionKey; TimeId _topPromotionNextRequestTime = TimeId(0); base::Timer _topPromotionTimer; base::flat_set> _updateNotifyTopics; base::flat_set> _updateNotifyPeers; base::flat_set _updateNotifyDefaults; base::Timer _updateNotifyTimer; rpl::lifetime _updateNotifyQueueLifetime; std::map< Data::FileOrigin, std::vector> _fileReferenceHandlers; mtpRequestId _deepLinkInfoRequestId = 0; crl::time _termsUpdateSendAt = 0; mtpRequestId _termsUpdateRequestId = 0; mtpRequestId _checkInviteRequestId = 0; mtpRequestId _checkFilterInviteRequestId = 0; struct MigrateCallbacks { FnMut)> done; Fn fail; }; base::flat_map< not_null, std::vector> _migrateCallbacks; struct { mtpRequestId requestId = 0; QString requestedText; } _bio; const std::unique_ptr _authorizations; const std::unique_ptr _attachedStickers; const std::unique_ptr _blockedPeers; const std::unique_ptr _cloudPassword; const std::unique_ptr _selfDestruct; const std::unique_ptr _sensitiveContent; const std::unique_ptr _globalPrivacy; const std::unique_ptr _userPrivacy; const std::unique_ptr _inviteLinks; const std::unique_ptr _views; const std::unique_ptr _confirmPhone; const std::unique_ptr _peerPhoto; const std::unique_ptr _polls; const std::unique_ptr _chatParticipants; const std::unique_ptr _unreadThings; const std::unique_ptr _ringtones; const std::unique_ptr _transcribes; const std::unique_ptr _premium; const std::unique_ptr _usernames; mtpRequestId _wallPaperRequestId = 0; QString _wallPaperSlug; Fn _wallPaperDone; Fn _wallPaperFail; mtpRequestId _contactSignupSilentRequestId = 0; std::optional _contactSignupSilent; rpl::event_stream _contactSignupSilentChanges; base::flat_map< not_null, std::vector>> _botCommonGroups; base::flat_map, Fn> _botCommonGroupsRequests; base::flat_map _unlikelyMessageLinks; base::flat_map _unlikelyStoryLinks; };