diff --git a/Telegram/Resources/scheme.tl b/Telegram/Resources/scheme.tl index a0aca70b5..c56618710 100644 --- a/Telegram/Resources/scheme.tl +++ b/Telegram/Resources/scheme.tl @@ -153,10 +153,13 @@ inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#179be863 chat_id:int = InputPeer; inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer; inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer; +inputPeerUserFromMessage#17bae2e6 peer:InputPeer msg_id:int user_id:int = InputPeer; +inputPeerChannelFromMessage#9c95f7bb peer:InputPeer msg_id:int channel_id:int = InputPeer; inputUserEmpty#b98886cf = InputUser; inputUserSelf#f7c1b13f = InputUser; inputUser#d8292816 user_id:int access_hash:long = InputUser; +inputUserFromMessage#2d117597 peer:InputPeer msg_id:int user_id:int = InputUser; inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact; @@ -229,11 +232,11 @@ userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#3bda1bde flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; chatForbidden#7328bdb id:int title:string = Chat; -channel#4df30834 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat; +channel#4df30834 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#1b7c9db3 flags:# can_set_username:flags.7?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int = ChatFull; -channelFull#3648977 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int pts:int = ChatFull; +channelFull#9882e516 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.13?int pts:int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; @@ -246,8 +249,8 @@ chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#475cdbd5 photo_small:FileLocation photo_big:FileLocation dc_id:int = ChatPhoto; messageEmpty#83e5de54 id:int = Message; -message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message; -messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; +message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message; +messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; @@ -353,7 +356,7 @@ messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector< messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; messages.messages#8c718e87 messages:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesSlice#a6c47aaa flags:# inexact:flags.1?true count:int messages:Vector chats:Vector users:Vector = messages.Messages; +messages.messagesSlice#c8edce1e flags:# inexact:flags.1?true count:int next_rate:flags.0?int messages:Vector chats:Vector users:Vector = messages.Messages; messages.channelMessages#99262e37 flags:# inexact:flags.1?true pts:int count:int messages:Vector chats:Vector users:Vector = messages.Messages; messages.messagesNotModified#74535f21 count:int = messages.Messages; @@ -546,6 +549,7 @@ inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey; inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey; inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey; +inputPrivacyKeyPhoneNumber#352dafa = InputPrivacyKey; privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; privacyKeyChatInvite#500e6dfa = PrivacyKey; @@ -553,6 +557,7 @@ privacyKeyPhoneCall#3d662b7b = PrivacyKey; privacyKeyPhoneP2P#39491cc8 = PrivacyKey; privacyKeyForwards#69ec56a3 = PrivacyKey; privacyKeyProfilePhoto#96151fed = PrivacyKey; +privacyKeyPhoneNumber#d19ae46d = PrivacyKey; inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; @@ -560,6 +565,8 @@ inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; +inputPrivacyValueAllowChatParticipants#4c81c1ba chats:Vector = InputPrivacyRule; +inputPrivacyValueDisallowChatParticipants#d82363af chats:Vector = InputPrivacyRule; privacyValueAllowContacts#fffe1bac = PrivacyRule; privacyValueAllowAll#65427b82 = PrivacyRule; @@ -567,8 +574,10 @@ privacyValueAllowUsers#4d5bbe0c users:Vector = PrivacyRule; privacyValueDisallowContacts#f888fa1a = PrivacyRule; privacyValueDisallowAll#8b73e763 = PrivacyRule; privacyValueDisallowUsers#c7f49b7 users:Vector = PrivacyRule; +privacyValueAllowChatParticipants#18be796b chats:Vector = PrivacyRule; +privacyValueDisallowChatParticipants#acae0690 chats:Vector = PrivacyRule; -account.privacyRules#554abb6f rules:Vector users:Vector = account.PrivacyRules; +account.privacyRules#50a04e45 rules:Vector chats:Vector users:Vector = account.PrivacyRules; accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; @@ -592,7 +601,6 @@ messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMess contactLinkUnknown#5f4f9247 = ContactLink; contactLinkNone#feedd3ad = ContactLink; -contactLinkHasPhone#268f3f59 = ContactLink; contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; @@ -640,6 +648,8 @@ keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton; keyboardButtonGame#50f41ccf text:string = KeyboardButton; keyboardButtonBuy#afd93fbb text:string = KeyboardButton; +keyboardButtonUrlAuth#10b78d29 flags:# text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton; +inputKeyboardButtonUrlAuth#d02e7fd4 flags:# request_write_access:flags.0?true text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton; keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; @@ -666,6 +676,7 @@ messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#afeb712e channel_id:int access_hash:long = InputChannel; +inputChannelFromMessage#2a286531 peer:InputPeer msg_id:int channel_id:int = InputChannel; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; @@ -761,6 +772,8 @@ topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; topPeerCategoryGroups#bd17a14a = TopPeerCategory; topPeerCategoryChannels#161d9628 = TopPeerCategory; topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; +topPeerCategoryForwardUsers#a8406ca9 = TopPeerCategory; +topPeerCategoryForwardChats#fbeec0f0 = TopPeerCategory; topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; @@ -945,6 +958,7 @@ channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputSticker channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction; channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction; +channelAdminLogEventActionChangeLinkedChat#a26f881b prev_value:int new_value:int = ChannelAdminLogEventAction; channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent; @@ -1145,6 +1159,12 @@ inputFolderPeer#fbd2c296 peer:InputPeer folder_id:int = InputFolderPeer; folderPeer#e9baa668 peer:Peer folder_id:int = FolderPeer; +messages.searchCounter#e844ebff flags:# inexact:flags.1?true filter:MessagesFilter count:int = messages.SearchCounter; + +urlAuthResultRequest#92d33a0e flags:# request_write_access:flags.0?true bot:User domain:string = UrlAuthResult; +urlAuthResultAccepted#8f8c0e4e url:string = UrlAuthResult; +urlAuthResultDefault#a9d6db1f = UrlAuthResult; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -1243,7 +1263,7 @@ contacts.unblock#e54100bd id:InputUser = Bool; contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked; contacts.search#11f812d8 q:string limit:int = contacts.Found; contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer; -contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; +contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers; contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; contacts.resetSaved#879537f1 = Bool; contacts.getSaved#82f1e39f = Vector; @@ -1297,7 +1317,7 @@ messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_par messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector increment:Bool = Vector; messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#15a3b8e3 chat_id:int = Updates; -messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; +messages.searchGlobal#f79c611 q:string offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector = Bool; messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs; @@ -1359,6 +1379,9 @@ messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference; messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference; messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector = Vector; messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL; +messages.getSearchCounters#732eef00 peer:InputPeer filters:Vector = Vector; +messages.requestUrlAuth#e33f5613 peer:InputPeer msg_id:int button_id:int = UrlAuthResult; +messages.acceptUrlAuth#f729ea98 flags:# write_allowed:flags.0?true peer:InputPeer msg_id:int button_id:int = UrlAuthResult; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; @@ -1427,6 +1450,9 @@ channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool; channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; +channels.getGroupsForDiscussion#f5dad378 = messages.Chats; +channels.getBroadcastsForDiscussion#1a87f304 = messages.Chats; +channels.setDiscussionGroup#40582bb2 broadcast:InputChannel group:InputChannel = Bool; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; @@ -1461,4 +1487,4 @@ langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLangua folders.editPeerFolders#6847d0ab folder_peers:Vector = Updates; folders.deleteFolder#1c295881 folder_id:int = Updates; -// LAYER 99 +// LAYER 100 diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 125e9976b..d824a289c 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -185,6 +185,26 @@ MTPInputPrivacyKey ApiWrap::Privacy::Input(Key key) { Unexpected("Key in ApiWrap::Privacy::Input."); } +std::optional ApiWrap::Privacy::KeyFromMTP( + mtpTypeId type) { + using Key = Privacy::Key; + switch (type) { + case mtpc_privacyKeyStatusTimestamp: + case mtpc_inputPrivacyKeyStatusTimestamp: return Key::LastSeen; + case mtpc_privacyKeyChatInvite: + case mtpc_inputPrivacyKeyChatInvite: return Key::Invites; + case mtpc_privacyKeyPhoneCall: + case mtpc_inputPrivacyKeyPhoneCall: return Key::Calls; + case mtpc_privacyKeyPhoneP2P: + case mtpc_inputPrivacyKeyPhoneP2P: return Key::CallsPeer2Peer; + case mtpc_privacyKeyForwards: + case mtpc_inputPrivacyKeyForwards: return Key::Forwards; + case mtpc_privacyKeyProfilePhoto: + case mtpc_inputPrivacyKeyProfilePhoto: return Key::ProfilePhoto; + } + return std::nullopt; +} + ApiWrap::ApiWrap(not_null session) : _session(session) , _messageDataResolveDelayed([=] { resolveMessageDatas(); }) @@ -2276,7 +2296,9 @@ void ApiWrap::saveDraftToCloudDelayed(not_null history) { } } -void ApiWrap::savePrivacy(const MTPInputPrivacyKey &key, QVector &&rules) { +void ApiWrap::savePrivacy( + const MTPInputPrivacyKey &key, + QVector &&rules) { const auto keyTypeId = key.type(); const auto it = _privacySaveRequests.find(keyTypeId); if (it != _privacySaveRequests.cend()) { @@ -2288,12 +2310,14 @@ void ApiWrap::savePrivacy(const MTPInputPrivacyKey &key, QVector(std::move(rules)) )).done([=](const MTPaccount_PrivacyRules &result) { - Expects(result.type() == mtpc_account_privacyRules); - - auto &rules = result.c_account_privacyRules(); - _session->data().processUsers(rules.vusers); - _privacySaveRequests.remove(keyTypeId); - handlePrivacyChange(keyTypeId, rules.vrules); + result.match([&](const MTPDaccount_privacyRules &data) { + _session->data().processUsers(data.vusers); + _session->data().processChats(data.vchats); + _privacySaveRequests.remove(keyTypeId); + if (const auto key = Privacy::KeyFromMTP(keyTypeId)) { + handlePrivacyChange(*key, data.vrules); + } + }); }).fail([=](const RPCError &error) { _privacySaveRequests.remove(keyTypeId); }).send(); @@ -2302,80 +2326,16 @@ void ApiWrap::savePrivacy(const MTPInputPrivacyKey &key, QVector &rules) { - using Key = Privacy::Key; - const auto key = [&]() -> std::optional { - switch (keyTypeId) { - case mtpc_privacyKeyStatusTimestamp: - case mtpc_inputPrivacyKeyStatusTimestamp: return Key::LastSeen; - case mtpc_privacyKeyChatInvite: - case mtpc_inputPrivacyKeyChatInvite: return Key::Invites; - case mtpc_privacyKeyPhoneCall: - case mtpc_inputPrivacyKeyPhoneCall: return Key::Calls; - case mtpc_privacyKeyPhoneP2P: - case mtpc_inputPrivacyKeyPhoneP2P: return Key::CallsPeer2Peer; - case mtpc_privacyKeyForwards: - case mtpc_inputPrivacyKeyForwards: return Key::Forwards; - case mtpc_privacyKeyProfilePhoto: - case mtpc_inputPrivacyKeyProfilePhoto: return Key::ProfilePhoto; - } - return std::nullopt; - }(); - if (!key) { - return; - } - pushPrivacy(*key, rules.v); - if (*key == Key::LastSeen) { + pushPrivacy(key, rules.v); + if (key == Privacy::Key::LastSeen) { updatePrivacyLastSeens(rules.v); } } void ApiWrap::updatePrivacyLastSeens(const QVector &rules) { - enum class Rule { - Unknown, - Allow, - Disallow, - }; - auto userRules = QMap(); - auto contactsRule = Rule::Unknown; - auto everyoneRule = Rule::Unknown; - for (auto &rule : rules) { - 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(); + const auto now = unixtime(); _session->data().enumerateUsers([&](UserData *user) { if (user->isSelf() || user->loadedStatus != PeerData::FullLoaded) { return; @@ -5642,6 +5602,7 @@ void ApiWrap::reloadPrivacy(Privacy::Key key) { _privacyRequestIds.erase(key); result.match([&](const MTPDaccount_privacyRules &data) { _session->data().processUsers(data.vusers); + _session->data().processChats(data.vchats); pushPrivacy(key, data.vrules.v); }); }).fail([=](const RPCError &error) { @@ -5664,8 +5625,10 @@ auto ApiWrap::parsePrivacy(const QVector &rules) optionSet = true; result.option = option; }; - auto &always = result.always; - auto &never = result.never; + auto &alwaysUsers = result.alwaysUsers; + auto &neverUsers = result.neverUsers; + auto &alwaysChats = result.alwaysChats; + auto &neverChats = result.neverChats; const auto Feed = [&](const MTPPrivacyRule &rule) { rule.match([&](const MTPDprivacyValueAllowAll &) { SetOption(Option::Everyone); @@ -5673,12 +5636,25 @@ auto ApiWrap::parsePrivacy(const QVector &rules) SetOption(Option::Contacts); }, [&](const MTPDprivacyValueAllowUsers &data) { const auto &users = data.vusers.v; - always.reserve(always.size() + users.size()); + alwaysUsers.reserve(alwaysUsers.size() + users.size()); for (const auto userId : users) { const auto user = _session->data().user(UserId(userId.v)); - if (!base::contains(never, user) - && !base::contains(always, user)) { - always.push_back(user); + if (!base::contains(neverUsers, user) + && !base::contains(alwaysUsers, user)) { + alwaysUsers.push_back(user); + } + } + }, [&](const MTPDprivacyValueAllowChatParticipants &data) { + const auto &chats = data.vchats.v; + alwaysChats.reserve(alwaysChats.size() + chats.size()); + for (const auto chatId : chats) { + const auto chat = _session->data().chatLoaded(chatId.v); + const auto peer = chat + ? static_cast(chat) + : _session->data().channel(chatId.v); + if (!base::contains(neverChats, peer) + && !base::contains(alwaysChats, peer)) { + alwaysChats.emplace_back(peer); } } }, [&](const MTPDprivacyValueDisallowContacts &) { @@ -5687,12 +5663,25 @@ auto ApiWrap::parsePrivacy(const QVector &rules) SetOption(Option::Nobody); }, [&](const MTPDprivacyValueDisallowUsers &data) { const auto &users = data.vusers.v; - never.reserve(never.size() + users.size()); + neverUsers.reserve(neverUsers.size() + users.size()); for (const auto userId : users) { const auto user = _session->data().user(UserId(userId.v)); - if (!base::contains(always, user) - && !base::contains(never, user)) { - never.push_back(user); + if (!base::contains(alwaysUsers, user) + && !base::contains(neverUsers, user)) { + neverUsers.push_back(user); + } + } + }, [&](const MTPDprivacyValueDisallowChatParticipants &data) { + const auto &chats = data.vchats.v; + neverChats.reserve(neverChats.size() + chats.size()); + for (const auto chatId : chats) { + const auto chat = _session->data().chatLoaded(chatId.v); + const auto peer = chat + ? static_cast(chat) + : _session->data().channel(chatId.v); + if (!base::contains(alwaysChats, peer) + && !base::contains(neverChats, peer)) { + neverChats.emplace_back(peer); } } }); diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 7b7a99782..da9044913 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -60,6 +60,30 @@ inline int32 CountHash(IntRange &&range) { class ApiWrap : public MTP::Sender, private base::Subscriber { public: + struct Privacy { + enum class Key { + LastSeen, + Calls, + Invites, + CallsPeer2Peer, + Forwards, + ProfilePhoto, + }; + enum class Option { + Everyone, + Contacts, + Nobody, + }; + Option option = Option::Everyone; + std::vector> alwaysUsers; + std::vector> neverUsers; + std::vector> alwaysChats; + std::vector> neverChats; + + static MTPInputPrivacyKey Input(Key key); + static std::optional KeyFromMTP(mtpTypeId type); + }; + ApiWrap(not_null session); void applyUpdates(const MTPUpdates &updates, uint64 sentMessageRandomId = 0); @@ -214,8 +238,12 @@ public: void updateNotifySettingsDelayed(not_null peer); void saveDraftToCloudDelayed(not_null history); - void savePrivacy(const MTPInputPrivacyKey &key, QVector &&rules); - void handlePrivacyChange(mtpTypeId keyTypeId, const MTPVector &rules); + void savePrivacy( + const MTPInputPrivacyKey &key, + QVector &&rules); + void handlePrivacyChange( + Privacy::Key key, + const MTPVector &rules); static int OnlineTillFromStatus( const MTPUserStatus &status, int currentOnlineTill); @@ -401,26 +429,6 @@ public: void saveSelfBio(const QString &text, FnMut done); - struct Privacy { - enum class Key { - 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); - }; void reloadPrivacy(Privacy::Key key); rpl::producer privacyValue(Privacy::Key key); diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index cbab3e830..9365fd7d0 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -148,9 +148,6 @@ namespace App { case mtpc_contactLinkContact: user->setContactStatus(UserData::ContactStatus::Contact); break; - case mtpc_contactLinkHasPhone: - user->setContactStatus(UserData::ContactStatus::CanAdd); - break; case mtpc_contactLinkNone: case mtpc_contactLinkUnknown: user->setContactStatus(UserData::ContactStatus::PhoneUnknown); diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp index bc8172cab..10d6603cf 100644 --- a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp @@ -142,23 +142,41 @@ void EditPrivacyBox::editExceptionUsers( } QVector EditPrivacyBox::collectResult() { - auto collectInputUsers = [](auto &users) { + const auto collectInputUsers = [](const auto &users) { auto result = QVector(); result.reserve(users.size()); - for (auto user : users) { + for (const auto user : users) { result.push_back(user->inputUser); } return result; }; + const auto collectInputChats = [](const auto & chats) { + auto result = QVector(); + result.reserve(chats.size()); + for (const auto peer : chats) { + result.push_back(MTP_int(peer->bareId())); + } + return result; + }; constexpr auto kMaxRules = 3; // allow users, disallow users, option auto result = QVector(); result.reserve(kMaxRules); - if (showExceptionLink(Exception::Always) && !_value.always.empty()) { - result.push_back(MTP_inputPrivacyValueAllowUsers(MTP_vector(collectInputUsers(_value.always)))); + if (showExceptionLink(Exception::Always)) { + if (!_value.alwaysUsers.empty()) { + result.push_back(MTP_inputPrivacyValueAllowUsers(MTP_vector(collectInputUsers(_value.alwaysUsers)))); + } + if (!_value.alwaysChats.empty()) { + result.push_back(MTP_inputPrivacyValueAllowChatParticipants(MTP_vector(collectInputChats(_value.alwaysChats)))); + } } - if (showExceptionLink(Exception::Never) && !_value.never.empty()) { - result.push_back(MTP_inputPrivacyValueDisallowUsers(MTP_vector(collectInputUsers(_value.never)))); + if (showExceptionLink(Exception::Never)) { + if (!_value.neverUsers.empty()) { + result.push_back(MTP_inputPrivacyValueDisallowUsers(MTP_vector(collectInputUsers(_value.neverUsers)))); + } + if (!_value.neverChats.empty()) { + result.push_back(MTP_inputPrivacyValueDisallowChatParticipants(MTP_vector(collectInputChats(_value.neverChats)))); + } } result.push_back([&] { switch (_value.option) { @@ -172,10 +190,11 @@ QVector EditPrivacyBox::collectResult() { return result; } +// #TODO privacy std::vector> &EditPrivacyBox::exceptionUsers(Exception exception) { switch (exception) { - case Exception::Always: return _value.always; - case Exception::Never: return _value.never; + case Exception::Always: return _value.alwaysUsers; + case Exception::Never: return _value.neverUsers; } Unexpected("Invalid exception value."); } @@ -309,7 +328,8 @@ void EditPrivacyBox::setupContent() { addButton(langFactory(lng_settings_save), [=] { const auto someAreDisallowed = (_value.option != Option::Everyone) - || !_value.never.empty(); + || !_value.neverUsers.empty() + || !_value.neverChats.empty(); _controller->confirmSave(someAreDisallowed, crl::guard(this, [=] { Auth().api().savePrivacy( _controller->apiKey(), diff --git a/Telegram/SourceFiles/chat_helpers/message_field.cpp b/Telegram/SourceFiles/chat_helpers/message_field.cpp index 5b86e006f..73be90b1a 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.cpp +++ b/Telegram/SourceFiles/chat_helpers/message_field.cpp @@ -212,7 +212,7 @@ EntitiesInText ConvertTextTagsToEntities(const TextWithTags::Tags &tags) { push(EntityType::Italic); } else if (tag.id == Ui::InputField::kTagCode) { push(EntityType::Code); - } else if (tag.id == Ui::InputField::kTagPre) { + } else if (tag.id == Ui::InputField::kTagPre) { // #TODO entities push(EntityType::Pre); } else /*if (ValidateUrl(tag.id)) */{ // We validate when we insert. push(EntityType::CustomUrl, tag.id); @@ -247,7 +247,7 @@ TextWithTags::Tags ConvertEntitiesToTextTags(const EntitiesInText &entities) { } } break; case EntityType::Bold: push(Ui::InputField::kTagBold); break; - case EntityType::Italic: push(Ui::InputField::kTagItalic); break; + case EntityType::Italic: push(Ui::InputField::kTagItalic); break; // #TODO entities case EntityType::Code: push(Ui::InputField::kTagCode); break; case EntityType::Pre: push(Ui::InputField::kTagPre); break; } diff --git a/Telegram/SourceFiles/codegen/scheme/codegen_scheme.py b/Telegram/SourceFiles/codegen/scheme/codegen_scheme.py index 9e64b39e9..f5533327b 100644 --- a/Telegram/SourceFiles/codegen/scheme/codegen_scheme.py +++ b/Telegram/SourceFiles/codegen/scheme/codegen_scheme.py @@ -168,7 +168,7 @@ for line in lines: templ = re.match(r'^([vV]ector<)([A-Za-z0-9\._]+)>$', restype); if (templ): vectemplate = templ.group(2); - if (re.match(r'^[A-Z]', vectemplate) or re.match(r'^[a-zA-Z0-9]+_[A-Z]', vectemplate)): + if (re.match(r'^[A-Z]', vectemplate) or re.match(r'^[a-zA-Z0-9]+\.[A-Z]', vectemplate)): restype = templ.group(1) + 'MTP' + vectemplate.replace('.', '_') + '>'; elif (vectemplate == 'int' or vectemplate == 'long' or vectemplate == 'string' or vectemplate == 'bytes'): restype = templ.group(1) + 'MTP' + vectemplate.replace('.', '_') + '>'; @@ -254,7 +254,7 @@ for line in lines: templ = re.match(r'^([vV]ector<)([A-Za-z0-9\._]+)>$', ptype); if (templ): vectemplate = templ.group(2); - if (re.match(r'^[A-Z]', vectemplate) or re.match(r'^[a-zA-Z0-9]+_[A-Z]', vectemplate)): + if (re.match(r'^[A-Z]', vectemplate) or re.match(r'^[a-zA-Z0-9]+\.[A-Z]', vectemplate)): ptype = templ.group(1) + 'MTP' + vectemplate.replace('.', '_') + '>'; elif (vectemplate == 'int' or vectemplate == 'long' or vectemplate == 'string' or vectemplate == 'bytes'): ptype = templ.group(1) + 'MTP' + vectemplate.replace('.', '_') + '>'; @@ -284,7 +284,7 @@ for line in lines: templ = re.match(r'^([vV]ector<)([A-Za-z0-9\._]+)>$', ptype); if (templ): vectemplate = templ.group(2); - if (re.match(r'^[A-Z]', vectemplate) or re.match(r'^[a-zA-Z0-9]+_[A-Z]', vectemplate)): + if (re.match(r'^[A-Z]', vectemplate) or re.match(r'^[a-zA-Z0-9]+\.[A-Z]', vectemplate)): ptype = templ.group(1) + 'MTP' + vectemplate.replace('.', '_') + '>'; elif (vectemplate == 'int' or vectemplate == 'long' or vectemplate == 'string' or vectemplate == 'bytes'): ptype = templ.group(1) + 'MTP' + vectemplate.replace('.', '_') + '>'; diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 80c9cd672..7a9a76591 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -479,7 +479,7 @@ not_null Session::processChat(const MTPChat &data) { const auto &migratedTo = data.has_migrated_to() ? data.vmigrated_to : MTPInputChannel(MTP_inputChannelEmpty()); - migratedTo.match([&](const MTPDinputChannel &input) { + migratedTo.match([&](const MTPDinputChannel & input) { const auto channel = this->channel(input.vchannel_id.v); channel->addFlags(MTPDchannel::Flag::f_megagroup); if (!channel->access) { @@ -490,6 +490,8 @@ not_null Session::processChat(const MTPChat &data) { channel->access = input.vaccess_hash.v; } ApplyMigration(chat, channel); + }, [](const MTPDinputChannelFromMessage &) { + LOG(("API Error: migrated_to contains channel from message.")); }, [](const MTPDinputChannelEmpty &) { }); diff --git a/Telegram/SourceFiles/export/data/export_data_types.h b/Telegram/SourceFiles/export/data/export_data_types.h index 08c9f6145..588fc2fae 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.h +++ b/Telegram/SourceFiles/export/data/export_data_types.h @@ -441,6 +441,9 @@ struct ActionSecureValuesSent { struct ActionContactSignUp { }; +struct ActionPhoneNumberRequest { +}; + struct ServiceAction { base::optional_variant< ActionChatCreate, @@ -462,7 +465,8 @@ struct ServiceAction { ActionCustomAction, ActionBotAllowed, ActionSecureValuesSent, - ActionContactSignUp> content; + ActionContactSignUp, + ActionPhoneNumberRequest> content; }; ServiceAction ParseServiceAction( @@ -487,6 +491,9 @@ struct TextPart { MentionName, Phone, Cashtag, + Underline, + Strike, + Blockquote }; Type type = Type::Text; Utf8String text; diff --git a/Telegram/SourceFiles/export/export_api_wrap.cpp b/Telegram/SourceFiles/export/export_api_wrap.cpp index d7b3bbd52..dc649a264 100644 --- a/Telegram/SourceFiles/export/export_api_wrap.cpp +++ b/Telegram/SourceFiles/export/export_api_wrap.cpp @@ -1081,6 +1081,10 @@ void ApiWrap::requestSinglePeerDialog() { )).done(std::move(doneSinglePeer)).send(); }, [&](const MTPDinputPeerSelf &data) { requestUser(MTP_inputUserSelf()); + }, [&](const MTPDinputPeerUserFromMessage &data) { + Unexpected("From message peer in ApiWrap::requestSinglePeerDialog."); + }, [&](const MTPDinputPeerChannelFromMessage &data) { + Unexpected("From message peer in ApiWrap::requestSinglePeerDialog."); }, [](const MTPDinputPeerEmpty &data) { Unexpected("Empty peer in ApiWrap::requestSinglePeerDialog."); }); diff --git a/Telegram/SourceFiles/export/output/export_output_html.cpp b/Telegram/SourceFiles/export/output/export_output_html.cpp index 4a38c3095..17dc6d19e 100644 --- a/Telegram/SourceFiles/export/output/export_output_html.cpp +++ b/Telegram/SourceFiles/export/output/export_output_html.cpp @@ -283,6 +283,10 @@ QByteArray FormatText( "onclick=\"return ShowCashtag(" + SerializeString('"' + text.mid(1) + '"') + ")\">" + text + ""; + case Type::Underline: return "" + text + ""; + case Type::Strike: return "" + text + ""; + case Type::Blockquote: + return "
" + text + "
"; } Unexpected("Type in text entities serialization."); }) | ranges::to_vector); @@ -1082,6 +1086,8 @@ auto HtmlWriter::Wrap::pushMessage( + SerializeList(list); }, [&](const ActionContactSignUp &data) { return serviceFrom + " joined Telegram"; + }, [&](const ActionPhoneNumberRequest &data) { + return serviceFrom + " requested your phone number"; }, [](std::nullopt_t) { return QByteArray(); }); if (!serviceText.isEmpty()) { diff --git a/Telegram/SourceFiles/export/output/export_output_json.cpp b/Telegram/SourceFiles/export/output/export_output_json.cpp index c5c674f26..fbdbf82ea 100644 --- a/Telegram/SourceFiles/export/output/export_output_json.cpp +++ b/Telegram/SourceFiles/export/output/export_output_json.cpp @@ -172,6 +172,9 @@ QByteArray SerializeText( case Type::MentionName: return "mention_name"; case Type::Phone: return "phone"; case Type::Cashtag: return "cashtag"; + case Type::Underline: return "underline"; + case Type::Strike: return "strikethrough"; + case Type::Blockquote: return "blockquote"; } Unexpected("Type in SerializeText."); }(); @@ -462,6 +465,9 @@ QByteArray SerializeMessage( }, [&](const ActionContactSignUp &data) { pushActor(); pushAction("joined_telegram"); + }, [&](const ActionPhoneNumberRequest &data) { + pushActor(); + pushAction("requested_phone_number"); }, [](std::nullopt_t) {}); if (!message.action.content) { diff --git a/Telegram/SourceFiles/export/output/export_output_text.cpp b/Telegram/SourceFiles/export/output/export_output_text.cpp index e9766cc75..be0ebd507 100644 --- a/Telegram/SourceFiles/export/output/export_output_text.cpp +++ b/Telegram/SourceFiles/export/output/export_output_text.cpp @@ -335,6 +335,9 @@ QByteArray SerializeMessage( }, [&](const ActionContactSignUp &data) { pushActor(); pushAction("Join Telegram"); + }, [&](const ActionPhoneNumberRequest &data) { + pushActor(); + pushAction("Request Phone Number"); }, [](std::nullopt_t) {}); if (!message.action.content) { diff --git a/Telegram/SourceFiles/export/view/export_view_settings.cpp b/Telegram/SourceFiles/export/view/export_view_settings.cpp index ea51f9be8..37559fbef 100644 --- a/Telegram/SourceFiles/export/view/export_view_settings.cpp +++ b/Telegram/SourceFiles/export/view/export_view_settings.cpp @@ -36,10 +36,14 @@ constexpr auto kMegabyte = 1024 * 1024; PeerId ReadPeerId(const MTPInputPeer &data) { return data.match([](const MTPDinputPeerUser &data) { return peerFromUser(data.vuser_id.v); + }, [](const MTPDinputPeerUserFromMessage &data) { + return peerFromUser(data.vuser_id.v); }, [](const MTPDinputPeerChat &data) { return peerFromChat(data.vchat_id.v); }, [](const MTPDinputPeerChannel &data) { return peerFromChannel(data.vchannel_id.v); + }, [](const MTPDinputPeerChannelFromMessage &data) { + return peerFromChannel(data.vchannel_id.v); }, [](const MTPDinputPeerSelf &data) { return Auth().userPeerId(); }, [](const MTPDinputPeerEmpty &data) { diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp index 2cd53af05..eea0d3652 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp @@ -616,6 +616,8 @@ void GenerateItems( createDefaultBannedRights(data); }, [&](const MTPDchannelAdminLogEventActionStopPoll &data) { createStopPoll(data); + }, [&](const MTPDchannelAdminLogEventActionChangeLinkedChat &data) { + // #TODO discussion }); } diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 33aa11807..1b20579cd 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -68,7 +68,7 @@ not_null CreateUnsupportedMessage( text.entities.push_front( EntityInText(EntityType::Italic, 0, text.text.size())); flags &= ~MTPDmessage::Flag::f_post_author; - flags |= MTPDmessage_ClientFlag::f_is_unsupported; + flags |= MTPDmessage::Flag::f_legacy; return history->owner().makeMessage( history, msgId, diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index 7e37f7405..35ee9620b 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -618,7 +618,7 @@ bool HistoryMessage::allowsEdit(TimeId now) const { return canStopPoll() && !isTooOldForEdit(now) && (!_media || _media->allowsEdit()) - && !isUnsupportedMessage() + && !isLegacyMessage() && !isEditingMedia(); } diff --git a/Telegram/SourceFiles/history/history_message.h b/Telegram/SourceFiles/history/history_message.h index e622b40f6..80c34e68e 100644 --- a/Telegram/SourceFiles/history/history_message.h +++ b/Telegram/SourceFiles/history/history_message.h @@ -150,8 +150,8 @@ private: return _flags & MTPDmessage_ClientFlag::f_has_admin_badge; } bool isTooOldForEdit(TimeId now) const; - bool isUnsupportedMessage() const { - return _flags & MTPDmessage_ClientFlag::f_is_unsupported; + bool isLegacyMessage() const { + return _flags & MTPDmessage::Flag::f_legacy; } // For an invoice button we replace the button text with a "Receipt" key. diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 02e49a8d6..13e9cfcb6 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -4292,7 +4292,36 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { case mtpc_updatePrivacy: { auto &d = update.c_updatePrivacy(); - session().api().handlePrivacyChange(d.vkey.type(), d.vrules); + const auto allChatsLoaded = [&](const MTPVector &ids) { + for (const auto &chatId : ids.v) { + if (!session().data().chatLoaded(chatId.v) + && !session().data().channelLoaded(chatId.v)) { + return false; + } + } + return true; + }; + const auto allLoaded = [&] { + for (const auto &rule : d.vrules.v) { + const auto loaded = rule.match([&]( + const MTPDprivacyValueAllowChatParticipants & data) { + return allChatsLoaded(data.vchats); + }, [&](const MTPDprivacyValueDisallowChatParticipants & data) { + return allChatsLoaded(data.vchats); + }, [](auto &&) { return true; }); + if (!loaded) { + return false; + } + } + return true; + }; + if (const auto key = ApiWrap::Privacy::KeyFromMTP(d.vkey.type())) { + if (allLoaded()) { + session().api().handlePrivacyChange(*key, d.vrules); + } else { + session().api().reloadPrivacy(*key); + } + } } break; case mtpc_updatePinnedDialogs: { diff --git a/Telegram/SourceFiles/mtproto/type_utils.h b/Telegram/SourceFiles/mtproto/type_utils.h index 802560212..824913fda 100644 --- a/Telegram/SourceFiles/mtproto/type_utils.h +++ b/Telegram/SourceFiles/mtproto/type_utils.h @@ -69,11 +69,8 @@ enum class MTPDmessage_ClientFlag : uint32 { // message has an admin badge in supergroup f_has_admin_badge = (1U << 20), - // message is unsupported by a current version of client - f_is_unsupported = (1U << 19), - // update this when adding new client side flags - MIN_FIELD = (1U << 19), + MIN_FIELD = (1U << 20), }; DEFINE_MTP_CLIENT_FLAGS(MTPDmessage) diff --git a/Telegram/SourceFiles/settings/settings_privacy_security.cpp b/Telegram/SourceFiles/settings/settings_privacy_security.cpp index be7cd9575..8bd0ec76e 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_security.cpp +++ b/Telegram/SourceFiles/settings/settings_privacy_security.cpp @@ -102,10 +102,10 @@ void SetupPrivacy(not_null container) { key ) | rpl::map([=](const Privacy &value) { auto add = QStringList(); - if (const auto never = value.never.size()) { + if (const auto never = value.neverUsers.size()) { // #TODO privacy add.push_back("-" + QString::number(never)); } - if (const auto always = value.always.size()) { + if (const auto always = value.alwaysUsers.size()) { add.push_back("+" + QString::number(always)); } if (!add.isEmpty()) { diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index 8715d0bd3..660bf6289 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -4715,14 +4715,14 @@ void WriteExportSettings(const Export::Settings &settings) { << quint32(settings.format) << settings.path << quint32(settings.availableAt); - settings.singlePeer.match([&](const MTPDinputPeerUser &user) { + settings.singlePeer.match([&](const MTPDinputPeerUser & user) { data.stream << kSinglePeerTypeUser << qint32(user.vuser_id.v) << quint64(user.vaccess_hash.v); - }, [&](const MTPDinputPeerChat &chat) { + }, [&](const MTPDinputPeerChat & chat) { data.stream << kSinglePeerTypeChat << qint32(chat.vchat_id.v); - }, [&](const MTPDinputPeerChannel &channel) { + }, [&](const MTPDinputPeerChannel & channel) { data.stream << kSinglePeerTypeChannel << qint32(channel.vchannel_id.v) @@ -4731,6 +4731,10 @@ void WriteExportSettings(const Export::Settings &settings) { data.stream << kSinglePeerTypeSelf; }, [&](const MTPDinputPeerEmpty &) { data.stream << kSinglePeerTypeEmpty; + }, [&](const MTPDinputPeerUserFromMessage &) { + Unexpected("From message peer in single peer export settings."); + }, [&](const MTPDinputPeerChannelFromMessage &) { + Unexpected("From message peer in single peer export settings."); }); data.stream << qint32(settings.singlePeerFrom); data.stream << qint32(settings.singlePeerTill); diff --git a/Telegram/SourceFiles/ui/image/image_location.cpp b/Telegram/SourceFiles/ui/image/image_location.cpp index 8ae994e61..335f64740 100644 --- a/Telegram/SourceFiles/ui/image/image_location.cpp +++ b/Telegram/SourceFiles/ui/image/image_location.cpp @@ -12,18 +12,35 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "storage/cache/storage_cache_types.h" #include "storage/serialize_common.h" #include "data/data_file_origin.h" +#include "base/overload.h" #include "auth_session.h" namespace { constexpr auto kDocumentBaseCacheTag = 0x0000000000010000ULL; constexpr auto kDocumentBaseCacheMask = 0x000000000000FF00ULL; +constexpr auto kSerializeTypeShift = quint8(0x08); -MTPInputPeer GenerateInputPeer(uint64 id, uint64 accessHash, int32 self) { +MTPInputPeer GenerateInputPeer( + uint64 id, + uint64 accessHash, + int32 inMessagePeerId, + int32 inMessageId, + int32 self) { const auto bareId = [&] { return peerToBareMTPInt(id); }; - if (!id) { + if (inMessagePeerId > 0 && inMessageId) { + return MTP_inputPeerUserFromMessage( + GenerateInputPeer(id, accessHash, 0, 0, self), + MTP_int(inMessageId), + MTP_int(inMessagePeerId)); + } else if (inMessagePeerId < 0 && inMessageId) { + return MTP_inputPeerChannelFromMessage( + GenerateInputPeer(id, accessHash, 0, 0, self), + MTP_int(inMessageId), + MTP_int(-inMessagePeerId)); + } else if (!id) { return MTP_inputPeerEmpty(); } else if (id == peerFromUser(self)) { return MTP_inputPeerSelf(); @@ -98,19 +115,36 @@ StorageFileLocation::StorageFileLocation( : data.vthumb_size.v[0]; }, [&](const MTPDinputPeerPhotoFileLocation &data) { _type = Type::PeerPhoto; - data.vpeer.match([&](const MTPDinputPeerEmpty &data) { + const auto fillPeer = base::overload([&]( + const MTPDinputPeerEmpty &data) { _id = 0; - }, [&](const MTPDinputPeerSelf &data) { + }, [&](const MTPDinputPeerSelf & data) { _id = peerFromUser(self); - }, [&](const MTPDinputPeerChat &data) { + }, [&](const MTPDinputPeerChat & data) { _id = peerFromChat(data.vchat_id); - }, [&](const MTPDinputPeerUser &data) { + }, [&](const MTPDinputPeerUser & data) { _id = peerFromUser(data.vuser_id); _accessHash = data.vaccess_hash.v; - }, [&](const MTPDinputPeerChannel &data) { + }, [&](const MTPDinputPeerChannel & data) { _id = peerFromChannel(data.vchannel_id); _accessHash = data.vaccess_hash.v; }); + data.vpeer.match(fillPeer, [&]( + const MTPDinputPeerUserFromMessage &data) { + data.vpeer.match(fillPeer, [&](auto &&) { + // Bad data provided. + _id = _accessHash = 0; + }); + _inMessagePeerId = data.vuser_id.v; + _inMessageId = data.vmsg_id.v; + }, [&](const MTPDinputPeerChannelFromMessage &data) { + data.vpeer.match(fillPeer, [&](auto &&) { + // Bad data provided. + _id = _accessHash = 0; + }); + _inMessagePeerId = -data.vchannel_id.v; + _inMessageId = data.vmsg_id.v; + }); _volumeId = data.vvolume_id.v; _localId = data.vlocal_id.v; _sizeLetter = data.is_big() ? 'c' : 'a'; @@ -195,7 +229,12 @@ MTPInputFileLocation StorageFileLocation::tl(int32 self) const { MTP_flags((_sizeLetter == 'c') ? MTPDinputPeerPhotoFileLocation::Flag::f_big : MTPDinputPeerPhotoFileLocation::Flag(0)), - GenerateInputPeer(_id, _accessHash, self), + GenerateInputPeer( + _id, + _accessHash, + _inMessagePeerId, + _inMessageId, + self), MTP_long(_volumeId), MTP_int(_localId)); @@ -219,12 +258,14 @@ QByteArray StorageFileLocation::serialize() const { stream.setVersion(QDataStream::Qt_5_1); stream << quint16(_dcId) - << quint8(_type) + << (kSerializeTypeShift | quint8(_type)) << quint8(_sizeLetter) << qint32(_localId) << quint64(_id) << quint64(_accessHash) << quint64(_volumeId) + << qint32(_inMessagePeerId) + << qint32(_inMessageId) << _fileReference; } return result; @@ -232,12 +273,12 @@ QByteArray StorageFileLocation::serialize() const { int StorageFileLocation::serializeSize() const { return valid() - ? int(sizeof(uint64) * 4 + Serialize::bytearraySize(_fileReference)) + ? int(sizeof(uint64) * 5 + Serialize::bytearraySize(_fileReference)) : 0; } std::optional StorageFileLocation::FromSerialized( - const QByteArray &serialized) { + const QByteArray &serialized) { if (serialized.isEmpty()) { return StorageFileLocation(); } @@ -249,6 +290,8 @@ std::optional StorageFileLocation::FromSerialized( quint64 id = 0; quint64 accessHash = 0; quint64 volumeId = 0; + qint32 inMessagePeerId = 0; + qint32 inMessageId = 0; QByteArray fileReference; auto stream = QDataStream(serialized); stream.setVersion(QDataStream::Qt_5_1); @@ -259,8 +302,12 @@ std::optional StorageFileLocation::FromSerialized( >> localId >> id >> accessHash - >> volumeId - >> fileReference; + >> volumeId; + if (type & kSerializeTypeShift) { + type &= ~kSerializeTypeShift; + stream >> inMessagePeerId >> inMessageId; + } + stream >> fileReference; auto result = StorageFileLocation(); result._dcId = dcId; @@ -270,6 +317,8 @@ std::optional StorageFileLocation::FromSerialized( result._id = id; result._accessHash = accessHash; result._volumeId = volumeId; + result._inMessagePeerId = inMessagePeerId; + result._inMessageId = inMessageId; result._fileReference = fileReference; return (stream.status() == QDataStream::Ok && result.valid()) ? std::make_optional(result) diff --git a/Telegram/SourceFiles/ui/image/image_location.h b/Telegram/SourceFiles/ui/image/image_location.h index 1527459be..c65f64616 100644 --- a/Telegram/SourceFiles/ui/image/image_location.h +++ b/Telegram/SourceFiles/ui/image/image_location.h @@ -107,6 +107,8 @@ private: uint64 _id = 0; uint64 _accessHash = 0; uint64 _volumeId = 0; + uint32 _inMessagePeerId = 0; // > 0 'userId', < 0 '-channelId'. + uint32 _inMessageId = 0; QByteArray _fileReference; }; diff --git a/Telegram/SourceFiles/ui/text/text.cpp b/Telegram/SourceFiles/ui/text/text.cpp index 0a8a61333..ba656f4c3 100644 --- a/Telegram/SourceFiles/ui/text/text.cpp +++ b/Telegram/SourceFiles/ui/text/text.cpp @@ -259,7 +259,7 @@ public: startFlags = TextBlockFSemibold; } else if (type == EntityType::Italic) { startFlags = TextBlockFItalic; - } else if (type == EntityType::Code) { + } else if (type == EntityType::Code) { // #TODO entities startFlags = TextBlockFCode; } else if (type == EntityType::Pre) { startFlags = TextBlockFPre; @@ -538,7 +538,7 @@ public: if (((type == EntityType::Mention || type == EntityType::MentionName) && !parseMentions) || (type == EntityType::Hashtag && !parseHashtags) || (type == EntityType::Cashtag && !parseHashtags) || - (type == EntityType::BotCommand && !parseBotCommands) || + (type == EntityType::BotCommand && !parseBotCommands) || // #TODO entities ((type == EntityType::Bold || type == EntityType::Italic || type == EntityType::Code || type == EntityType::Pre) && !parseMarkdown)) { continue; } @@ -3077,7 +3077,7 @@ TextForMimeData Text::toText( ? std::vector{ { TextBlockFItalic, EntityType::Italic }, { TextBlockFSemibold, EntityType::Bold }, - { TextBlockFCode, EntityType::Code }, + { TextBlockFCode, EntityType::Code }, // #TODO entities { TextBlockFPre, EntityType::Pre } } : std::vector(); const auto flagsChangeCallback = [&](int32 oldFlags, int32 newFlags) { diff --git a/Telegram/SourceFiles/ui/text/text_entity.cpp b/Telegram/SourceFiles/ui/text/text_entity.cpp index 1ccd0014e..800bafc07 100644 --- a/Telegram/SourceFiles/ui/text/text_entity.cpp +++ b/Telegram/SourceFiles/ui/text/text_entity.cpp @@ -1322,7 +1322,7 @@ bool CutPart(TextWithEntities &sending, TextWithEntities &left, int32 limit) { if (s > half) { bool inEntity = (currentEntity < entityCount) && (ch > start + left.entities[currentEntity].offset()) && (ch < start + left.entities[currentEntity].offset() + left.entities[currentEntity].length()); EntityType entityType = (currentEntity < entityCount) ? left.entities[currentEntity].type() : EntityType::Invalid; - bool canBreakEntity = (entityType == EntityType::Pre || entityType == EntityType::Code); + bool canBreakEntity = (entityType == EntityType::Pre || entityType == EntityType::Code); // #TODO entities int32 noEntityLevel = inEntity ? 0 : 1; auto markGoodAsLevel = [&](int newLevel) { @@ -1502,6 +1502,7 @@ EntitiesInText EntitiesFromMTP(const QVector &entities) { case mtpc_messageEntityItalic: { auto &d = entity.c_messageEntityItalic(); result.push_back({ EntityType::Italic, d.voffset.v, d.vlength.v }); } break; case mtpc_messageEntityCode: { auto &d = entity.c_messageEntityCode(); result.push_back({ EntityType::Code, d.voffset.v, d.vlength.v }); } break; case mtpc_messageEntityPre: { auto &d = entity.c_messageEntityPre(); result.push_back({ EntityType::Pre, d.voffset.v, d.vlength.v, Clean(qs(d.vlanguage)) }); } break; + // #TODO entities } } } @@ -1516,7 +1517,7 @@ MTPVector EntitiesToMTP(const EntitiesInText &entities, Conver if (option == ConvertOption::SkipLocal && entity.type() != EntityType::Bold && entity.type() != EntityType::Italic - && entity.type() != EntityType::Code + && entity.type() != EntityType::Code // #TODO entities && entity.type() != EntityType::Pre && entity.type() != EntityType::MentionName && entity.type() != EntityType::CustomUrl) { @@ -1549,7 +1550,7 @@ MTPVector EntitiesToMTP(const EntitiesInText &entities, Conver case EntityType::BotCommand: v.push_back(MTP_messageEntityBotCommand(offset, length)); break; case EntityType::Bold: v.push_back(MTP_messageEntityBold(offset, length)); break; case EntityType::Italic: v.push_back(MTP_messageEntityItalic(offset, length)); break; - case EntityType::Code: v.push_back(MTP_messageEntityCode(offset, length)); break; + case EntityType::Code: v.push_back(MTP_messageEntityCode(offset, length)); break; // #TODO entities case EntityType::Pre: v.push_back(MTP_messageEntityPre(offset, length, MTP_string(entity.data()))); break; } }