diff --git a/CMakeLists.txt b/CMakeLists.txt index a4ab431e7..0641182bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -550,6 +550,7 @@ set(TDLIB_SOURCE td/telegram/files/PartsManager.h td/telegram/files/ResourceManager.h td/telegram/files/ResourceState.h + td/telegram/FolderId.h td/telegram/Game.h td/telegram/Global.h td/telegram/HashtagHints.h diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 52ef4b794..3a036c91b 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -604,9 +604,19 @@ chatTypeSupergroup supergroup_id:int32 is_channel:Bool = ChatType; chatTypeSecret secret_chat_id:int32 user_id:int32 = ChatType; +//@class ChatListType @description Describes a list of chats a chat belongs to + +//@description A main list of chats. Can contain ordinary chats and other lists of chats as folders +chatListTypeMain = ChatListType; + +//@description A list of chats located at the top of main chat list. Unmuted chats are automatically moved from the Archive to the Main chat list +chatListTypeArchive = ChatListType; + + //@description A chat. (Can be a private chat, basic group, supergroup, or secret chat) //@id Chat unique identifier //@type Type of the chat +//@list_type The type of a chat list the chat belongs to; may be null //@title Chat title //@photo Chat photo; may be null //@permissions Actions that non-administrator chat members are allowed to take in the chat @@ -628,7 +638,7 @@ chatTypeSecret secret_chat_id:int32 user_id:int32 = ChatType; //@reply_markup_message_id Identifier of the message from which reply markup needs to be used; 0 if there is no default custom reply markup in the chat //@draft_message A draft of a message in the chat; may be null //@client_data Contains client-specific data associated with the chat. (For example, the chat position or local chat notification settings can be stored here.) Persistent if a message database is used -chat id:int53 type:ChatType title:string photo:chatPhoto permissions:chatPermissions last_message:message order:int64 is_pinned:Bool is_marked_as_unread:Bool is_sponsored:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings pinned_message_id:int53 reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat; +chat id:int53 type:ChatType list_type:ChatListType title:string photo:chatPhoto permissions:chatPermissions last_message:message order:int64 is_pinned:Bool is_marked_as_unread:Bool is_sponsored:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings pinned_message_id:int53 reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat; //@description Represents a list of chats @chat_ids List of chat identifiers chats chat_ids:vector = Chats; @@ -2595,6 +2605,9 @@ updateMessageMentionRead chat_id:int53 message_id:int53 unread_mention_count:int //@description A new chat has been loaded/created. This update is guaranteed to come before the chat identifier is returned to the client. The chat field changes will be reported through separate updates @chat The chat updateNewChat chat:chat = Update; +//@description The list to which the chat belongs was changed @chat_id Chat identifier @list_type The new chat list type; may be null +updateChatListType chat_id:int53 list_type:ChatListType = Update; + //@description The title of a chat was changed @chat_id Chat identifier @title The new chat title updateChatTitle chat_id:int53 title:string = Update; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index daa7b5657..7030f619c 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/generate/scheme/telegram_api.tl b/td/generate/scheme/telegram_api.tl index e278fc94e..8c15a2d79 100644 --- a/td/generate/scheme/telegram_api.tl +++ b/td/generate/scheme/telegram_api.tl @@ -31,10 +31,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; @@ -110,8 +113,8 @@ 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; 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#22a235da 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 = ChatFull; -channelFull#1c87a71a 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 = ChatFull; +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; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; @@ -164,7 +167,8 @@ messageActionSecureValuesSentMe#1b287353 values:Vector credentials: messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; messageActionContactSignUp#f3f25f76 = MessageAction; -dialog#e4def5db flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; +dialog#2c171f72 flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int = Dialog; +dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; photoEmpty#2331b22d id:long = Photo; photo#d07504a5 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector dc_id:int = Photo; @@ -203,7 +207,7 @@ inputReportReasonChildAbuse#adf44ee3 = ReportReason; inputReportReasonOther#e1746d0a text:string = ReportReason; inputReportReasonCopyright#9b89f93a = ReportReason; -userFull#8ea4a881 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int = UserFull; +userFull#745559cc flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; @@ -278,14 +282,14 @@ updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; updateUserPhone#12b9417b user_id:int phone:string = Update; -updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update; +updateReadHistoryInbox#9c974fdf flags:# folder_id:flags.0?int peer:Peer max_id:int still_unread_count:int pts:int pts_count:int = Update; updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; updateReadMessagesContents#68c13933 messages:Vector pts:int pts_count:int = Update; updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update; updateChannel#b6d45656 channel_id:int = Update; updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; -updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update; +updateReadChannelInbox#330b5424 flags:# folder_id:flags.0?int channel_id:int max_id:int still_unread_count:int pts:int = Update; updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector pts:int pts_count:int = Update; updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update; updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update; @@ -307,8 +311,8 @@ updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; updatePtsChanged#3354678f = Update; updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update; -updateDialogPinned#19d27f3c flags:# pinned:flags.0?true peer:DialogPeer = Update; -updatePinnedDialogs#ea4cb65b flags:# order:flags.0?Vector = Update; +updateDialogPinned#6e6fe51c flags:# pinned:flags.0?true folder_id:flags.1?int peer:DialogPeer = Update; +updatePinnedDialogs#fa0f3ca2 flags:# folder_id:flags.1?int order:flags.0?Vector = Update; updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update; @@ -325,6 +329,7 @@ updateUserPinnedMessage#4c43da18 user_id:int id:int = Update; updateChatPinnedMessage#e10db349 chat_id:int id:int version:int = Update; updateMessagePoll#aca1657b flags:# poll_id:long poll:flags.0?Poll results:PollResults = Update; updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update; +updateFolderPeers#19360dc0 folder_peers:Vector pts:int pts_count:int = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -351,7 +356,7 @@ upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; -config#e6ca25f6 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true pfs_enabled:flags.13?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int = Config; +config#330b4067 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true pfs_enabled:flags.13?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int pinned_infolder_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; @@ -542,13 +547,14 @@ 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; messageRange#ae30253 min_id:int max_id:int = MessageRange; updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; -updates.channelDifferenceTooLong#6a9d7b35 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int messages:Vector chats:Vector users:Vector = updates.ChannelDifference; +updates.channelDifferenceTooLong#a4bcc6fe flags:# final:flags.0?true timeout:flags.1?int dialog:Dialog messages:Vector chats:Vector users:Vector = updates.ChannelDifference; updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; @@ -852,8 +858,10 @@ inputMessageReplyTo#bad88395 id:int = InputMessage; inputMessagePinned#86872538 = InputMessage; inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; +inputDialogPeerFolder#64600527 folder_id:int = InputDialogPeer; dialogPeer#e56dbf05 peer:Peer = DialogPeer; +dialogPeerFolder#514519e2 folder_id:int = DialogPeer; messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; messages.foundStickerSets#5108d648 hash:int sets:Vector = messages.FoundStickerSets; @@ -1017,6 +1025,12 @@ wallet.secretSalt#dd484d64 salt:bytes = wallet.KeySecretSalt; fileLocationToBeDeprecated#bc7fc6cd volume_id:long local_id:int = FileLocation; +folder#ff544e65 flags:# autofill_new_broadcasts:flags.0?true autofill_public_groups:flags.1?true autofill_new_correspondents:flags.2?true id:int title:string photo:flags.3?ChatPhoto = Folder; + +inputFolderPeer#fbd2c296 peer:InputPeer folder_id:int = InputFolderPeer; + +folderPeer#e9baa668 peer:Peer folder_id:int = FolderPeer; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -1122,7 +1136,7 @@ contacts.getSaved#82f1e39f = Vector; contacts.toggleTopPeers#8514bdda enabled:Bool = Bool; messages.getMessages#63c66506 id:Vector = messages.Messages; -messages.getDialogs#b098aee6 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs; +messages.getDialogs#a0ee3b73 flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs; messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; @@ -1202,8 +1216,8 @@ messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = message messages.getAllChats#eba80ff0 except_ids:Vector = messages.Chats; messages.getWebPage#32ca8f91 url:string hash:int = WebPage; messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; -messages.reorderPinnedDialogs#5b51d63f flags:# force:flags.0?true order:Vector = Bool; -messages.getPinnedDialogs#e254d64e = messages.PeerDialogs; +messages.reorderPinnedDialogs#3b1adf37 flags:# force:flags.0?true folder_id:int order:Vector = Bool; +messages.getPinnedDialogs#d6b94df2 folder_id:int = messages.PeerDialogs; messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia; @@ -1332,3 +1346,6 @@ langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector; langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage; + +folders.editPeerFolders#6847d0ab folder_peers:Vector = Updates; +folders.deleteFolder#1c295881 folder_id:int = Updates; diff --git a/td/generate/scheme/telegram_api.tlo b/td/generate/scheme/telegram_api.tlo index 865b58fcd..98946de23 100644 Binary files a/td/generate/scheme/telegram_api.tlo and b/td/generate/scheme/telegram_api.tlo differ diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index aa17df2e8..396e31033 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -6604,11 +6604,20 @@ void ContactsManager::on_get_user_full(tl_object_ptr &&u td_->messages_manager_->on_update_dialog_notify_settings(DialogId(user_id), std::move(user_full->notify_settings_), "on_get_user_full"); - MessageId pinned_message_id; - if ((user_full->flags_ & USER_FULL_FLAG_HAS_PINNED_MESSAGE) != 0) { - pinned_message_id = MessageId(ServerMessageId(user_full->pinned_msg_id_)); + { + MessageId pinned_message_id; + if ((user_full->flags_ & USER_FULL_FLAG_HAS_PINNED_MESSAGE) != 0) { + pinned_message_id = MessageId(ServerMessageId(user_full->pinned_msg_id_)); + } + td_->messages_manager_->on_update_dialog_pinned_message_id(DialogId(user_id), pinned_message_id); + } + { + FolderId folder_id; + if ((user_full->flags_ & USER_FULL_FLAG_HAS_FOLDER_ID) != 0) { + folder_id = FolderId(user_full->folder_id_); + } + td_->messages_manager_->on_update_dialog_folder_id(DialogId(user_id), folder_id); } - td_->messages_manager_->on_update_dialog_pinned_message_id(DialogId(user_id), pinned_message_id); UserFull *user = &users_full_[user_id]; user->expires_at = Time::now() + USER_FULL_EXPIRE_TIME; @@ -6811,6 +6820,13 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c } } } + { + FolderId folder_id; + if ((chat_full->flags_ & CHAT_FULL_FLAG_HAS_FOLDER_ID) != 0) { + folder_id = FolderId(chat_full->folder_id_); + } + td_->messages_manager_->on_update_dialog_folder_id(DialogId(chat_id), folder_id); + } ChatFull *chat = &chats_full_[chat_id]; on_update_chat_full_invite_link(chat, std::move(chat_full->exported_invite_)); @@ -6912,11 +6928,20 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c on_update_channel_full_invite_link(channel, std::move(channel_full->exported_invite_)); - MessageId pinned_message_id; - if ((channel_full->flags_ & CHANNEL_FULL_FLAG_HAS_PINNED_MESSAGE) != 0) { - pinned_message_id = MessageId(ServerMessageId(channel_full->pinned_msg_id_)); + { + MessageId pinned_message_id; + if ((channel_full->flags_ & CHANNEL_FULL_FLAG_HAS_PINNED_MESSAGE) != 0) { + pinned_message_id = MessageId(ServerMessageId(channel_full->pinned_msg_id_)); + } + td_->messages_manager_->on_update_dialog_pinned_message_id(DialogId(channel_id), pinned_message_id); + } + { + FolderId folder_id; + if ((channel_full->flags_ & CHANNEL_FULL_FLAG_HAS_FOLDER_ID) != 0) { + folder_id = FolderId(channel_full->folder_id_); + } + td_->messages_manager_->on_update_dialog_folder_id(DialogId(channel_id), folder_id); } - td_->messages_manager_->on_update_dialog_pinned_message_id(DialogId(channel_id), pinned_message_id); if (participant_count >= 190) { int32 online_member_count = 0; diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 293c81567..cc27a529b 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -776,6 +776,7 @@ class ContactsManager : public Actor { static constexpr int32 USER_FULL_FLAG_HAS_BOT_INFO = 1 << 3; static constexpr int32 USER_FULL_FLAG_HAS_PINNED_MESSAGE = 1 << 6; static constexpr int32 USER_FULL_FLAG_CAN_PIN_MESSAGE = 1 << 7; + static constexpr int32 USER_FULL_FLAG_HAS_FOLDER_ID = 1 << 11; static constexpr int32 CHAT_FLAG_USER_IS_CREATOR = 1 << 0; static constexpr int32 CHAT_FLAG_USER_WAS_KICKED = 1 << 1; @@ -786,6 +787,7 @@ class ContactsManager : public Actor { static constexpr int32 CHAT_FLAG_WAS_MIGRATED = 1 << 6; static constexpr int32 CHAT_FULL_FLAG_HAS_PINNED_MESSAGE = 1 << 6; + static constexpr int32 CHAT_FULL_FLAG_HAS_FOLDER_ID = 1 << 11; static constexpr int32 CHANNEL_FLAG_USER_IS_CREATOR = 1 << 0; static constexpr int32 CHANNEL_FLAG_USER_HAS_LEFT = 1 << 2; @@ -815,6 +817,7 @@ class ContactsManager : public Actor { static constexpr int32 CHANNEL_FULL_FLAG_HAS_STICKER_SET = 1 << 8; static constexpr int32 CHANNEL_FULL_FLAG_HAS_AVAILABLE_MIN_MESSAGE_ID = 1 << 9; static constexpr int32 CHANNEL_FULL_FLAG_IS_ALL_HISTORY_HIDDEN = 1 << 10; + static constexpr int32 CHANNEL_FULL_FLAG_HAS_FOLDER_ID = 1 << 11; static constexpr int32 CHANNEL_FULL_FLAG_CAN_VIEW_STATISTICS = 1 << 12; static constexpr int32 CHANNEL_FULL_FLAG_HAS_ONLINE_MEMBER_COUNT = 1 << 13; diff --git a/td/telegram/DialogId.cpp b/td/telegram/DialogId.cpp index 0ccf068bc..0aa98ec87 100644 --- a/td/telegram/DialogId.cpp +++ b/td/telegram/DialogId.cpp @@ -103,8 +103,20 @@ DialogId::DialogId(SecretChatId chat_id) { } } -DialogId::DialogId(const tl_object_ptr &dialog_peer) { - id = get_peer_id(dialog_peer->peer_); +DialogId::DialogId(const tl_object_ptr &dialog_peer) { + CHECK(dialog_peer != nullptr); + switch (dialog_peer->get_id()) { + case telegram_api::dialogPeer::ID: + id = get_peer_id(static_cast(dialog_peer.get())->peer_); + break; + case telegram_api::dialogPeerFolder::ID: + LOG(ERROR) << "Receive unsupported " << to_string(dialog_peer); + id = 0; + break; + default: + id = 0; + UNREACHABLE(); + } } DialogId::DialogId(const tl_object_ptr &peer) : id(get_peer_id(peer)) { diff --git a/td/telegram/DialogId.h b/td/telegram/DialogId.h index 8fc1f5919..0e781f566 100644 --- a/td/telegram/DialogId.h +++ b/td/telegram/DialogId.h @@ -45,7 +45,7 @@ class DialogId { template ::value>> DialogId(T dialog_id) = delete; - explicit DialogId(const tl_object_ptr &dialog_peer); + explicit DialogId(const tl_object_ptr &dialog_peer); explicit DialogId(const tl_object_ptr &peer); explicit DialogId(UserId user_id); explicit DialogId(ChatId chat_id); diff --git a/td/telegram/FolderId.h b/td/telegram/FolderId.h new file mode 100644 index 000000000..1cf1f92ec --- /dev/null +++ b/td/telegram/FolderId.h @@ -0,0 +1,78 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2019 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/telegram/td_api.h" + +#include "td/utils/common.h" +#include "td/utils/StringBuilder.h" + +#include +#include + +namespace td { + +class FolderId { + int32 id = 0; + + public: + FolderId() = default; + + explicit FolderId(int32 folder_id) : id(folder_id) { + } + template ::value>> + FolderId(T folder_id) = delete; + + explicit FolderId(const td_api::object_ptr &chat_list) { + if (chat_list != nullptr && chat_list->get_id() == td_api::chatListArchive::ID) { + id = 1; + } else { + CHECK(id == 0); + } + } + + int32 get() const { + return id; + } + + bool operator==(const FolderId &other) const { + return id == other.id; + } + + bool operator!=(const FolderId &other) const { + return id != other.id; + } + + template + void store(StorerT &storer) const { + storer.store_int(id); + } + + template + void parse(ParserT &parser) { + id = parser.fetch_int(); + } + + static FolderId main() { + return FolderId(); + } + static FolderId archive() { + return FolderId(1); + } +}; + +struct FolderIdHash { + std::size_t operator()(FolderId folder_id) const { + return std::hash()(folder_id.get()); + } +}; + +inline StringBuilder &operator<<(StringBuilder &string_builder, FolderId folder_id) { + return string_builder << "folder " << folder_id.get(); +} + +} // namespace td diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 73e9e9070..d4b41f874 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -166,7 +166,7 @@ class GetPinnedDialogsActor : public NetActorOnce { } NetQueryRef send(uint64 sequence_id) { - auto query = G()->net_query_creator().create(create_storer(telegram_api::messages_getPinnedDialogs())); + auto query = G()->net_query_creator().create(create_storer(telegram_api::messages_getPinnedDialogs(0))); auto result = query.get_weak(); send_closure(td->messages_manager_->sequence_dispatcher_, &MultiSequenceDispatcher::send_with_callback, std::move(query), actor_shared(this), sequence_id); @@ -410,9 +410,10 @@ class GetDialogListActor : public NetActorOnce { input_peer = make_tl_object(); } - int32 flags = telegram_api::messages_getDialogs::EXCLUDE_PINNED_MASK; + int32 flags = + telegram_api::messages_getDialogs::EXCLUDE_PINNED_MASK | telegram_api::messages_getDialogs::FOLDER_ID_MASK; auto query = G()->net_query_creator().create(create_storer(telegram_api::messages_getDialogs( - flags, false /*ignored*/, offset_date, offset_message_id.get(), std::move(input_peer), limit, 0))); + flags, false /*ignored*/, 0, offset_date, offset_message_id.get(), std::move(input_peer), limit, 0))); send_closure(td->messages_manager_->sequence_dispatcher_, &MultiSequenceDispatcher::send_with_callback, std::move(query), actor_shared(this), sequence_id); } @@ -956,7 +957,7 @@ class ReorderPinnedDialogsQuery : public Td::ResultHandler { void send(const vector &dialog_ids) { int32 flags = telegram_api::messages_reorderPinnedDialogs::FORCE_MASK; send_query(G()->net_query_creator().create(create_storer(telegram_api::messages_reorderPinnedDialogs( - flags, true /*ignored*/, td->messages_manager_->get_input_dialog_peers(dialog_ids, AccessRights::Read))))); + flags, true /*ignored*/, 0, td->messages_manager_->get_input_dialog_peers(dialog_ids, AccessRights::Read))))); } void on_result(uint64 id, BufferSlice packet) override { @@ -3901,6 +3902,7 @@ void MessagesManager::Dialog::store(StorerT &storer) const { bool has_flags2 = true; bool has_max_notification_message_id = max_notification_message_id.is_valid() && max_notification_message_id.get() > last_new_message_id.get(); + bool has_folder_id = folder_id != FolderId(); BEGIN_STORE_FLAGS(); STORE_FLAG(has_draft_message); STORE_FLAG(has_last_database_message); @@ -3939,6 +3941,8 @@ void MessagesManager::Dialog::store(StorerT &storer) const { if (has_flags2) { BEGIN_STORE_FLAGS(); STORE_FLAG(has_max_notification_message_id); + STORE_FLAG(has_folder_id); + STORE_FLAG(is_folder_id_inited); END_STORE_FLAGS(); } @@ -4015,6 +4019,9 @@ void MessagesManager::Dialog::store(StorerT &storer) const { if (has_max_notification_message_id) { store(max_notification_message_id, storer); } + if (has_folder_id) { + store(folder_id, storer); + } } // do not forget to resolve dialog dependencies including dependencies of last_message @@ -4041,6 +4048,7 @@ void MessagesManager::Dialog::parse(ParserT &parser) { bool has_pinned_message_id; bool has_flags2; bool has_max_notification_message_id = false; + bool has_folder_id = false; BEGIN_PARSE_FLAGS(); PARSE_FLAG(has_draft_message); PARSE_FLAG(has_last_database_message); @@ -4079,6 +4087,8 @@ void MessagesManager::Dialog::parse(ParserT &parser) { if (has_flags2) { BEGIN_PARSE_FLAGS(); PARSE_FLAG(has_max_notification_message_id); + PARSE_FLAG(has_folder_id); + PARSE_FLAG(is_folder_id_inited); END_PARSE_FLAGS(); } @@ -4186,6 +4196,9 @@ void MessagesManager::Dialog::parse(ParserT &parser) { if (has_max_notification_message_id) { parse(max_notification_message_id, parser); } + if (has_folder_id) { + parse(folder_id, parser); + } } template @@ -4603,7 +4616,7 @@ vector> MessagesManager::get_input_peers( return input_peers; } -tl_object_ptr MessagesManager::get_input_dialog_peer(DialogId dialog_id, +tl_object_ptr MessagesManager::get_input_dialog_peer(DialogId dialog_id, AccessRights access_rights) const { switch (dialog_id.get_type()) { case DialogType::User: @@ -4619,9 +4632,9 @@ tl_object_ptr MessagesManager::get_input_dialog_p } } -vector> MessagesManager::get_input_dialog_peers( +vector> MessagesManager::get_input_dialog_peers( const vector &dialog_ids, AccessRights access_rights) const { - vector> input_dialog_peers; + vector> input_dialog_peers; input_dialog_peers.reserve(dialog_ids.size()); for (auto &dialog_id : dialog_ids) { auto input_dialog_peer = get_input_dialog_peer(dialog_id, access_rights); @@ -10707,28 +10720,52 @@ void MessagesManager::on_update_message_web_page(FullMessageId full_message_id, "on_update_message_web_page"); } -void MessagesManager::on_get_dialogs(vector> &&dialogs, int32 total_count, +void MessagesManager::on_get_dialogs(vector> &&dialog_folders, int32 total_count, vector> &&messages, Promise &&promise) { if (td_->updates_manager_->running_get_difference()) { LOG(INFO) << "Postpone result of getDialogs"; pending_on_get_dialogs_.push_back( - PendingOnGetDialogs{std::move(dialogs), total_count, std::move(messages), std::move(promise)}); + PendingOnGetDialogs{std::move(dialog_folders), total_count, std::move(messages), std::move(promise)}); return; } bool from_dialog_list = total_count >= 0; bool from_get_dialog = total_count == -1; bool from_pinned_dialog_list = total_count == -2; - if (from_get_dialog && dialogs.size() == 1) { - DialogId dialog_id(dialogs[0]->peer_); + if (from_get_dialog && dialog_folders.size() == 1 && dialog_folders[0]->get_id() == telegram_api::dialog::ID) { + DialogId dialog_id(static_cast(dialog_folders[0].get())->peer_); if (running_get_channel_difference(dialog_id)) { LOG(INFO) << "Postpone result of channels getDialogs for " << dialog_id; - pending_channel_on_get_dialogs_.emplace( - dialog_id, PendingOnGetDialogs{std::move(dialogs), total_count, std::move(messages), std::move(promise)}); + pending_channel_on_get_dialogs_.emplace(dialog_id, PendingOnGetDialogs{std::move(dialog_folders), total_count, + std::move(messages), std::move(promise)}); return; } } + vector> dialogs; + for (auto &dialog_folder : dialog_folders) { + switch (dialog_folder->get_id()) { + case telegram_api::dialog::ID: + dialogs.push_back(telegram_api::move_object_as(dialog_folder)); + break; + case telegram_api::dialogFolder::ID: { + auto folder = telegram_api::move_object_as(dialog_folder); + if (from_pinned_dialog_list) { + // TODO updata unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int + FolderId folder_id(folder->folder_->id_); + if (folder_id == FolderId::archive()) { + // archive is expected + break; + } + } + LOG(ERROR) << "Receive unexpected " << to_string(folder); + break; + } + default: + UNREACHABLE(); + } + } + LOG(INFO) << "Receive " << dialogs.size() << " dialogs out of " << total_count << " in result of GetDialogsQuery"; std::unordered_map full_message_id_to_dialog_date; std::unordered_map, FullMessageIdHash> full_message_id_to_message; @@ -10843,6 +10880,8 @@ void MessagesManager::on_get_dialogs(vector> } bool is_new = d->last_new_message_id == MessageId(); + set_dialog_folder_id(d, FolderId((dialog->flags_ & DIALOG_FLAG_HAS_PTS) != 0 ? dialog->folder_id_ : 0)); + on_update_dialog_notify_settings(dialog_id, std::move(dialog->notify_settings_), "on_get_dialogs"); if (!d->notification_settings.is_synchronized) { LOG(ERROR) << "Failed to synchronize settings in " << dialog_id; @@ -10874,6 +10913,10 @@ void MessagesManager::on_get_dialogs(vector> // TODO add pinned_message_id to telegram_api::dialog get_dialog_pinned_message(dialog_id, Auto()); } + if (!d->is_folder_id_inited && !td_->auth_manager_->is_bot()) { + // asynchronously get dialog folder message from the server + get_dialog_info_full(dialog_id, Auto()); + } need_update_dialog_pos |= update_dialog_draft_message( d, get_draft_message(td_->contacts_manager_.get(), std::move(dialog->draft_)), true, false); @@ -12269,6 +12312,26 @@ MessageId MessagesManager::get_replied_message(DialogId dialog_id, MessageId mes return replied_message_id; } +void MessagesManager::get_dialog_info_full(DialogId dialog_id, Promise &&promise) { + switch (dialog_id.get_type()) { + case DialogType::User: + td_->contacts_manager_->get_user_full(dialog_id.get_user_id(), std::move(promise)); + return; + case DialogType::Chat: + td_->contacts_manager_->get_chat_full(dialog_id.get_chat_id(), std::move(promise)); + return; + case DialogType::Channel: + td_->contacts_manager_->get_channel_full(dialog_id.get_channel_id(), std::move(promise)); + return; + case DialogType::SecretChat: + return promise.set_value(Unit()); + case DialogType::None: + default: + UNREACHABLE(); + return promise.set_error(Status::Error(500, "Wrong chat type")); + } +} + MessageId MessagesManager::get_dialog_pinned_message(DialogId dialog_id, Promise &&promise) { Dialog *d = get_dialog_force(dialog_id); if (d == nullptr) { @@ -12279,32 +12342,13 @@ MessageId MessagesManager::get_dialog_pinned_message(DialogId dialog_id, Promise LOG(INFO) << "Get pinned message in " << dialog_id << " with " << (d->is_pinned_message_id_inited ? "inited" : "unknown") << " pinned " << d->pinned_message_id; - Promise empty_promise; - auto &get_pinned_message_id_promise = d->is_pinned_message_id_inited ? empty_promise : promise; - switch (dialog_id.get_type()) { - case DialogType::User: - td_->contacts_manager_->get_user_full(dialog_id.get_user_id(), std::move(get_pinned_message_id_promise)); - break; - case DialogType::Chat: - td_->contacts_manager_->get_chat_full(dialog_id.get_chat_id(), std::move(get_pinned_message_id_promise)); - break; - case DialogType::Channel: { - td_->contacts_manager_->get_channel_full(dialog_id.get_channel_id(), std::move(get_pinned_message_id_promise)); - break; - } - case DialogType::SecretChat: - get_pinned_message_id_promise.set_value(Unit()); - return MessageId(); - case DialogType::None: - default: - UNREACHABLE(); - get_pinned_message_id_promise.set_error(Status::Error(500, "Wrong chat type")); - } if (!d->is_pinned_message_id_inited) { - // promise was already consumed + get_dialog_info_full(dialog_id, std::move(promise)); return MessageId(); } + get_dialog_info_full(dialog_id, Auto()); + tl_object_ptr input_message; if (dialog_id.get_type() == DialogType::Channel) { input_message = make_tl_object(); @@ -13756,25 +13800,25 @@ void MessagesManager::close_dialog(Dialog *d) { } } -tl_object_ptr MessagesManager::get_chat_type_object(DialogId dialog_id) const { +td_api::object_ptr MessagesManager::get_chat_type_object(DialogId dialog_id) const { switch (dialog_id.get_type()) { case DialogType::User: - return make_tl_object( + return td_api::make_object( td_->contacts_manager_->get_user_id_object(dialog_id.get_user_id(), "chatTypePrivate")); case DialogType::Chat: - return make_tl_object( + return td_api::make_object( td_->contacts_manager_->get_basic_group_id_object(dialog_id.get_chat_id(), "chatTypeBasicGroup")); case DialogType::Channel: { auto channel_id = dialog_id.get_channel_id(); auto channel_type = td_->contacts_manager_->get_channel_type(channel_id); - return make_tl_object( + return td_api::make_object( td_->contacts_manager_->get_supergroup_id_object(channel_id, "chatTypeSupergroup"), channel_type != ChannelType::Megagroup); } case DialogType::SecretChat: { auto secret_chat_id = dialog_id.get_secret_chat_id(); auto user_id = td_->contacts_manager_->get_secret_chat_user_id(secret_chat_id); - return make_tl_object( + return td_api::make_object( td_->contacts_manager_->get_secret_chat_id_object(secret_chat_id, "chatTypeSecret"), td_->contacts_manager_->get_user_id_object(user_id, "chatTypeSecret")); } @@ -13785,7 +13829,20 @@ tl_object_ptr MessagesManager::get_chat_type_object(DialogId d } } -tl_object_ptr MessagesManager::get_chat_object(const Dialog *d) const { +td_api::object_ptr MessagesManager::get_chat_list_type_object(const Dialog *d) { + if (d->order == DEFAULT_ORDER) { + return nullptr; + } + if (d->folder_id == FolderId::archive()) { + return td_api::make_object(); + } + if (d->folder_id != FolderId::main()) { + LOG(ERROR) << "Have " << d->dialog_id << " in unknown " << d->folder_id; + } + return td_api::make_object(); +} + +td_api::object_ptr MessagesManager::get_chat_object(const Dialog *d) const { CHECK(d != nullptr); bool can_delete_for_self = false; @@ -13830,8 +13887,8 @@ tl_object_ptr MessagesManager::get_chat_object(const Dialog *d) co } return make_tl_object( - d->dialog_id.get(), get_chat_type_object(d->dialog_id), get_dialog_title(d->dialog_id), - get_chat_photo_object(td_->file_manager_.get(), get_dialog_photo(d->dialog_id)), + d->dialog_id.get(), get_chat_type_object(d->dialog_id), get_chat_list_type_object(d), + get_dialog_title(d->dialog_id), get_chat_photo_object(td_->file_manager_.get(), get_dialog_photo(d->dialog_id)), get_dialog_permissions(d->dialog_id).get_chat_permissions_object(), get_message_object(d->dialog_id, get_message(d, d->last_message_id)), DialogDate(d->order, d->dialog_id) <= last_dialog_date_ ? d->order : 0, d->pinned_order != DEFAULT_ORDER, @@ -20620,6 +20677,12 @@ void MessagesManager::send_update_chat_online_member_count(DialogId dialog_id, i make_tl_object(dialog_id.get(), online_member_count)); } +void MessagesManager::send_update_chat_list_type(const Dialog *d) const { + LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_list_type"; + send_closure(G()->td(), &Td::send_update, + make_tl_object(d->dialog_id.get(), get_chat_list_type_object(d))); +} + void MessagesManager::on_send_message_get_quick_ack(int64 random_id) { auto it = being_sent_messages_.find(random_id); if (it == being_sent_messages_.end()) { @@ -21373,7 +21436,7 @@ void MessagesManager::on_update_dialog_pinned_message_id(DialogId dialog_id, Mes LOG(INFO) << "Pinned message in " << d->dialog_id << " is still " << pinned_message_id; if (!d->is_pinned_message_id_inited) { d->is_pinned_message_id_inited = true; - on_dialog_updated(d->dialog_id, "set_dialog_is_pinned_message_id_inited"); + on_dialog_updated(dialog_id, "on_update_dialog_pinned_message_id"); } return; } @@ -21394,6 +21457,38 @@ void MessagesManager::set_dialog_pinned_message_id(Dialog *d, MessageId pinned_m make_tl_object(d->dialog_id.get(), pinned_message_id.get())); } +void MessagesManager::on_update_dialog_folder_id(DialogId dialog_id, FolderId folder_id) { + auto d = get_dialog_force(dialog_id); + if (d == nullptr) { + // nothing to do + return; + } + + set_dialog_folder_id(d, folder_id); +} + +void MessagesManager::set_dialog_folder_id(Dialog *d, FolderId folder_id) { + CHECK(d != nullptr); + + if (d->folder_id == folder_id) { + LOG(INFO) << "Folder of " << d->dialog_id << " is still " << folder_id; + if (!d->is_folder_id_inited) { + d->is_folder_id_inited = true; + on_dialog_updated(d->dialog_id, "set_dialog_folder_id"); + } + return; + } + + d->folder_id = folder_id; + d->is_folder_id_inited = true; + on_dialog_updated(d->dialog_id, "set_dialog_folder_id"); + + LOG(INFO) << "Set " << d->dialog_id << " folder to " << folder_id; + if (d->order != DEFAULT_ORDER) { + send_update_chat_list_type(d); + } +} + void MessagesManager::on_create_new_dialog_success(int64 random_id, tl_object_ptr &&updates, DialogType expected_type, Promise &&promise) { auto sent_messages = UpdatesManager::get_new_messages(updates.get()); @@ -24895,6 +24990,7 @@ MessagesManager::Dialog *MessagesManager::add_new_dialog(unique_ptr &&d, d->is_last_read_outbox_message_id_inited = true; d->know_can_report_spam = true; d->is_pinned_message_id_inited = true; + d->is_folder_id_inited = true; if (!is_loaded_from_database) { d->can_report_spam = td_->contacts_manager_->default_can_report_spam_in_secret_chat(dialog_id.get_secret_chat_id()); @@ -24961,6 +25057,10 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab // asynchronously get dialog pinned message from the server get_dialog_pinned_message(dialog_id, Auto()); } + if (being_added_dialog_id_ != dialog_id && !d->is_folder_id_inited && !td_->auth_manager_->is_bot()) { + // asynchronously get dialog folder id from the server + get_dialog_info_full(dialog_id, Auto()); + } if (d->notification_settings.is_synchronized && !d->notification_settings.is_use_default_fixed && have_input_peer(dialog_id, AccessRights::Read) && !td_->auth_manager_->is_bot()) { @@ -25449,6 +25549,7 @@ bool MessagesManager::set_dialog_order(Dialog *d, int64 new_order, bool need_sen bool is_sponsored = (new_order == SPONSORED_DIALOG_ORDER); bool had_unread_counter = need_unread_counter(d->order); bool has_unread_counter = need_unread_counter(new_order); + bool need_update_folder = (d->order == DEFAULT_ORDER || new_order == DEFAULT_ORDER); if (!is_loaded_from_database && had_unread_counter != has_unread_counter && !td_->auth_manager_->is_bot()) { auto unread_count = d->server_unread_count + d->local_unread_count; @@ -25507,6 +25608,10 @@ bool MessagesManager::set_dialog_order(Dialog *d, int64 new_order, bool need_sen } update_dialogs_hints_rating(d); + if (need_update_folder) { + send_update_chat_list_type(d); + } + if (was_sponsored != is_sponsored) { send_update_chat_is_sponsored(d); if (!is_loaded_from_database && is_sponsored) { @@ -26095,13 +26200,35 @@ void MessagesManager::on_get_channel_difference( case telegram_api::updates_channelDifferenceTooLong::ID: { auto difference = move_tl_object_as(difference_ptr); + tl_object_ptr dialog; + switch (difference->dialog_->get_id()) { + case telegram_api::dialog::ID: + dialog = telegram_api::move_object_as(difference->dialog_); + break; + case telegram_api::dialogFolder::ID: + return after_get_channel_difference(dialog_id, false); + default: + UNREACHABLE(); + return; + } + + CHECK(dialog != nullptr); + if ((dialog->flags_ & telegram_api::dialog::PTS_MASK) == 0) { + LOG(ERROR) << "Receive " << dialog_id << " without pts"; + return after_get_channel_difference(dialog_id, false); + } + int32 flags = difference->flags_; is_final = (flags & CHANNEL_DIFFERENCE_FLAG_IS_FINAL) != 0; if (flags & CHANNEL_DIFFERENCE_FLAG_HAS_TIMEOUT) { timeout = difference->timeout_; } - auto new_pts = difference->pts_; + // TODO + // pinned:flags.2?true unread_mark:flags.3?true notify_settings:PeerNotifySettings + // draft:flags.1?DraftMessage folder_id:flags.4?int + + auto new_pts = dialog->pts_; if (request_pts + request_limit > new_pts) { LOG(ERROR) << "Receive channelDifferenceTooLong as result of getChannelDifference with pts = " << request_pts << " and limit = " << request_limit << " in " << dialog_id << ", but pts has changed from " << d->pts @@ -26114,10 +26241,9 @@ void MessagesManager::on_get_channel_difference( td_->contacts_manager_->on_get_users(std::move(difference->users_), "updates.channelDifferenceTooLong"); td_->contacts_manager_->on_get_chats(std::move(difference->chats_), "updates.channelDifferenceTooLong"); - on_get_channel_dialog(dialog_id, MessageId(ServerMessageId(difference->top_message_)), - MessageId(ServerMessageId(difference->read_inbox_max_id_)), difference->unread_count_, - difference->unread_mentions_count_, - MessageId(ServerMessageId(difference->read_outbox_max_id_)), + on_get_channel_dialog(dialog_id, MessageId(ServerMessageId(dialog->top_message_)), + MessageId(ServerMessageId(dialog->read_inbox_max_id_)), dialog->unread_count_, + dialog->unread_mentions_count_, MessageId(ServerMessageId(dialog->read_outbox_max_id_)), std::move(difference->messages_)); need_update_dialog_pos = true; diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 786c24ca8..8cc433faa 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -18,6 +18,7 @@ #include "td/telegram/DialogParticipant.h" #include "td/telegram/files/FileId.h" #include "td/telegram/files/FileSourceId.h" +#include "td/telegram/FolderId.h" #include "td/telegram/Global.h" #include "td/telegram/MessageContent.h" #include "td/telegram/MessageEntity.h" @@ -182,10 +183,10 @@ class MessagesManager : public Actor { vector> get_input_peers(const vector &dialog_ids, AccessRights access_rights) const; - tl_object_ptr get_input_dialog_peer(DialogId dialog_id, + tl_object_ptr get_input_dialog_peer(DialogId dialog_id, AccessRights access_rights) const; - vector> get_input_dialog_peers(const vector &dialog_ids, + vector> get_input_dialog_peers(const vector &dialog_ids, AccessRights access_rights) const; tl_object_ptr get_input_encrypted_chat(DialogId dialog_id, @@ -258,7 +259,7 @@ class MessagesManager : public Actor { void on_update_message_web_page(FullMessageId full_message_id, bool have_web_page); - void on_get_dialogs(vector> &&dialogs, int32 total_count, + void on_get_dialogs(vector> &&dialog_folders, int32 total_count, vector> &&messages, Promise &&promise); void on_get_common_dialogs(UserId user_id, int32 offset_chat_id, vector> &&chats, @@ -276,6 +277,8 @@ class MessagesManager : public Actor { void on_update_dialog_pinned_message_id(DialogId dialog_id, MessageId pinned_message_id); + void on_update_dialog_folder_id(DialogId dialog_id, FolderId folder_id); + void on_update_service_notification(tl_object_ptr &&update, bool skip_new_entities, Promise &&promise); @@ -982,6 +985,7 @@ class MessagesManager : public Actor { uint64 save_notification_settings_logevent_id_generation = 0; uint64 read_history_logevent_id = 0; uint64 read_history_logevent_id_generation = 0; + FolderId folder_id; MessageId last_read_all_mentions_message_id; // all mentions with a message id not greater than it are implicitly read @@ -1031,6 +1035,7 @@ class MessagesManager : public Actor { bool is_last_read_inbox_message_id_inited = false; bool is_last_read_outbox_message_id_inited = false; bool is_pinned_message_id_inited = false; + bool is_folder_id_inited = false; bool need_repair_server_unread_count = false; bool is_marked_as_unread = false; @@ -1306,6 +1311,7 @@ class MessagesManager : public Actor { static constexpr int32 DIALOG_FLAG_HAS_PTS = 1 << 0; static constexpr int32 DIALOG_FLAG_HAS_DRAFT = 1 << 1; static constexpr int32 DIALOG_FLAG_IS_PINNED = 1 << 2; + static constexpr int32 DIALOG_FLAG_HAS_FOLDER_ID = 1 << 4; static constexpr int32 MAX_MESSAGE_VIEW_DELAY = 1; // seconds static constexpr int32 MIN_SAVE_DRAFT_DELAY = 1; // seconds @@ -1739,6 +1745,8 @@ class MessagesManager : public Actor { void send_update_chat_online_member_count(DialogId dialog_id, int32 online_member_count) const; + void send_update_chat_list_type(const Dialog *d) const; + tl_object_ptr get_message_object(DialogId dialog_id, const Message *m, bool for_event_log = false) const; @@ -1788,6 +1796,8 @@ class MessagesManager : public Actor { void set_dialog_pinned_message_id(Dialog *d, MessageId pinned_message_id); + void set_dialog_folder_id(Dialog *d, FolderId folder_id); + void toggle_dialog_is_pinned_on_server(DialogId dialog_id, bool is_pinned, uint64 logevent_id); void toggle_dialog_is_marked_as_unread_on_server(DialogId dialog_id, bool is_marked_as_unread, uint64 logevent_id); @@ -1852,9 +1862,11 @@ class MessagesManager : public Actor { void add_dialog_last_database_message(Dialog *d, unique_ptr &&last_database_message); - tl_object_ptr get_chat_type_object(DialogId dialog_id) const; + td_api::object_ptr get_chat_type_object(DialogId dialog_id) const; - tl_object_ptr get_chat_object(const Dialog *d) const; + static td_api::object_ptr get_chat_list_type_object(const Dialog *d); + + td_api::object_ptr get_chat_object(const Dialog *d) const; bool have_dialog_info(DialogId dialog_id) const; bool have_dialog_info_force(DialogId dialog_id) const; @@ -1903,6 +1915,8 @@ class MessagesManager : public Actor { Message *on_get_message_from_database(DialogId dialog_id, Dialog *d, const BufferSlice &value, const char *source); + void get_dialog_info_full(DialogId dialog_id, Promise &&promise); + void get_dialog_message_by_date_from_server(const Dialog *d, int32 date, int64 random_id, bool after_database_search, Promise &&promise); @@ -2441,7 +2455,7 @@ class MessagesManager : public Actor { std::unordered_map inaccessible_resolved_usernames_; struct PendingOnGetDialogs { - vector> dialogs; + vector> dialogs; int32 total_count; vector> messages; Promise promise; diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index 122993a6a..4f60976f9 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -1880,4 +1880,7 @@ void UpdatesManager::on_update(tl_object_ptr up // unsupported updates +void UpdatesManager::on_update(tl_object_ptr update, bool /*force_apply*/) { +} + } // namespace td diff --git a/td/telegram/UpdatesManager.h b/td/telegram/UpdatesManager.h index 68be2446c..735d3c616 100644 --- a/td/telegram/UpdatesManager.h +++ b/td/telegram/UpdatesManager.h @@ -278,6 +278,8 @@ class UpdatesManager : public Actor { void on_update(tl_object_ptr update, bool /*force_apply*/); // unsupported updates + + void on_update(tl_object_ptr update, bool /*force_apply*/); }; } // namespace td diff --git a/td/telegram/Version.h b/td/telegram/Version.h index 3c4f988c8..915b8c406 100644 --- a/td/telegram/Version.h +++ b/td/telegram/Version.h @@ -8,7 +8,7 @@ namespace td { -constexpr int32 MTPROTO_LAYER = 98; +constexpr int32 MTPROTO_LAYER = 99; enum class Version : int32 { Initial, diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index c21e1efb4..82f0f304f 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -401,7 +401,8 @@ class CliClient final : public Actor { case td_api::authorizationStateWaitTdlibParameters::ID: { auto parameters = td_api::make_object(); parameters->use_test_dc_ = use_test_dc_; - parameters->use_message_database_ = true; + parameters->use_message_database_ = false; + parameters->use_chat_info_database_ = true; parameters->use_secret_chats_ = true; parameters->api_id_ = api_id_; parameters->api_hash_ = api_hash_;