Merge remote-tracking branch 'td/master'

This commit is contained in:
Andrea Cavalli 2022-12-14 16:10:30 +01:00
commit ab5a0774e7
63 changed files with 2825 additions and 739 deletions

View File

@ -155,6 +155,10 @@ function(td_set_up_compiler)
add_cxx_compiler_flag("-Wno-return-stack-address")
endif()
if (MINGW)
add_cxx_compiler_flag("-ftrack-macro-expansion=0")
endif()
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem /usr/include/c++/v1")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread")

View File

@ -6,7 +6,7 @@ if (POLICY CMP0065)
cmake_policy(SET CMP0065 NEW)
endif()
project(TDLib VERSION 1.8.8 LANGUAGES CXX C)
project(TDLib VERSION 1.8.9 LANGUAGES CXX C)
if (NOT DEFINED CMAKE_MODULE_PATH)
set(CMAKE_MODULE_PATH "")
@ -391,6 +391,7 @@ set(TDLIB_SOURCE
td/telegram/MessageReplyInfo.cpp
td/telegram/MessageSearchFilter.cpp
td/telegram/MessageSender.cpp
td/telegram/MessagesInfo.cpp
td/telegram/MessagesManager.cpp
td/telegram/MessageThreadDb.cpp
td/telegram/MessageTtl.cpp
@ -635,6 +636,7 @@ set(TDLIB_SOURCE
td/telegram/MessageReplyInfo.h
td/telegram/MessageSearchFilter.h
td/telegram/MessageSender.h
td/telegram/MessagesInfo.h
td/telegram/MessagesManager.h
td/telegram/MessageThreadDb.h
td/telegram/MessageThreadInfo.h
@ -763,8 +765,10 @@ set(TDLIB_SOURCE
td/telegram/files/FileLocation.hpp
td/telegram/files/FileManager.hpp
td/telegram/files/FileSourceId.hpp
td/telegram/ForumTopic.hpp
td/telegram/ForumTopicEditedData.hpp
td/telegram/ForumTopicIcon.hpp
td/telegram/ForumTopicInfo.hpp
td/telegram/Game.hpp
td/telegram/InputInvoice.hpp
td/telegram/InputMessageText.hpp

View File

@ -130,7 +130,7 @@ target_link_libraries(YourTarget PRIVATE Td::TdStatic)
Or you could install `TDLib` and then reference it in your CMakeLists.txt like this:
```
find_package(Td 1.8.8 REQUIRED)
find_package(Td 1.8.9 REQUIRED)
target_link_libraries(YourTarget PRIVATE Td::TdStatic)
```
See [example/cpp/CMakeLists.txt](https://github.com/tdlight-team/tdlight/blob/master/example/cpp/CMakeLists.txt).

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.4 FATAL_ERROR)
project(TdExample VERSION 1.0 LANGUAGES CXX)
find_package(Td 1.8.8 REQUIRED)
find_package(Td 1.8.9 REQUIRED)
add_executable(tdjson_example tdjson_example.cpp)
target_link_libraries(tdjson_example PRIVATE Td::TdJson)

View File

@ -1,6 +1,6 @@
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011">
<Metadata>
<Identity Id="Telegram.Td.UWP" Version="1.8.8" Language="en-US" Publisher="Telegram LLC" />
<Identity Id="Telegram.Td.UWP" Version="1.8.9" Language="en-US" Publisher="Telegram LLC" />
<DisplayName>TDLib for Universal Windows Platform</DisplayName>
<Description>TDLib is a library for building Telegram clients</Description>
<MoreInfo>https://core.telegram.org/tdlib</MoreInfo>

View File

@ -39,6 +39,9 @@ authenticationCodeTypeFlashCall pattern:string = AuthenticationCodeType;
//@description An authentication code is delivered by an immediately canceled call to the specified phone number. The last digits of the phone number that calls are the code that must be entered manually by the user @phone_number_prefix Prefix of the phone number from which the call will be made @length Number of digits in the code, excluding the prefix
authenticationCodeTypeMissedCall phone_number_prefix:string length:int32 = AuthenticationCodeType;
//@description An authentication code is delivered to https://fragment.com. The user must be logged in there via a wallet owning the phone number's NFT @url URL to open to receive the code @length Length of the code
authenticationCodeTypeFragment url:string length:int32 = AuthenticationCodeType;
//@description Information about the authentication code that was sent @phone_number A phone number that is being authenticated @type The way the code was sent to the user @next_type The way the next code will be sent to the user; may be null @timeout Timeout before the code can be re-sent, in seconds
authenticationCodeInfo phone_number:string type:AuthenticationCodeType next_type:AuthenticationCodeType timeout:int32 = AuthenticationCodeInfo;
@ -495,7 +498,7 @@ chatAdministratorRights can_manage_chat:Bool can_change_info:Bool can_post_messa
premiumPaymentOption currency:string amount:int53 discount_percentage:int32 month_count:int32 store_product_id:string payment_link:InternalLinkType = PremiumPaymentOption;
//@description Describes a custom emoji to be shown instead of the Telegram Premium badge @custom_emoji_id Identifier of the custom emoji in stickerFormatTgs format. If the custom emoji belongs to the sticker set GetOption("themed_emoji_statuses_sticker_set_id"), then it's color must be changed to the color of the Telegram Premium badge
//@description Describes a custom emoji to be shown instead of the Telegram Premium badge @custom_emoji_id Identifier of the custom emoji in stickerFormatTgs format. If the custom emoji belongs to the sticker set getOption("themed_emoji_statuses_sticker_set_id"), then it's color must be changed to the color of the Telegram Premium badge
emojiStatus custom_emoji_id:int64 = EmojiStatus;
//@description Contains a list of emoji statuses @emoji_statuses The list of emoji statuses
@ -523,14 +526,15 @@ usernames active_usernames:vector<string> disabled_usernames:vector<string> edit
//@is_verified True, if the user is verified
//@is_premium True, if the user is a Telegram Premium user
//@is_support True, if the user is Telegram support account
//@has_anonymous_phone_number True, if the user's phone number was bought on Fragment and isn't tied to a SIM card
//@restriction_reason If non-empty, it contains a human-readable description of the reason why access to this user must be restricted
//@is_scam True, if many users reported this user as a scam
//@is_fake True, if many users reported this user as a fake account
//@have_access If false, the user is inaccessible, and the only information known about the user is inside this class. Identifier of the user can't be passed to any method except GetUser
//@have_access If false, the user is inaccessible, and the only information known about the user is inside this class. Identifier of the user can't be passed to any method
//@type Type of the user
//@language_code IETF language tag of the user's language; only available to bots
//@added_to_attachment_menu True, if the user added the current bot to attachment menu; only available to bots
user id:int53 first_name:string last_name:string usernames:usernames phone_number:string status:UserStatus profile_photo:profilePhoto emoji_status:emojiStatus is_contact:Bool is_mutual_contact:Bool is_verified:Bool is_premium:Bool is_support:Bool restriction_reason:string is_scam:Bool is_fake:Bool have_access:Bool type:UserType language_code:string added_to_attachment_menu:Bool = User;
user id:int53 first_name:string last_name:string usernames:usernames phone_number:string status:UserStatus profile_photo:profilePhoto emoji_status:emojiStatus is_contact:Bool is_mutual_contact:Bool is_verified:Bool is_premium:Bool is_support:Bool has_anonymous_phone_number:Bool restriction_reason:string is_scam:Bool is_fake:Bool have_access:Bool type:UserType language_code:string added_to_attachment_menu:Bool = User;
//@description Contains information about a bot
@ -604,7 +608,7 @@ chatMemberStatusBanned banned_until_date:int32 = ChatMemberStatus;
//@description Describes a user or a chat as a member of another chat
//@member_id Identifier of the chat member. Currently, other chats can be only Left or Banned. Only supergroups and channels can have other chats as Left or Banned members and these chats must be supergroups or channels
//@inviter_user_id Identifier of a user that invited/promoted/banned this member in the chat; 0 if unknown
//@joined_chat_date Point in time (Unix timestamp) when the user joined the chat
//@joined_chat_date Point in time (Unix timestamp) when the user joined/was promoted/was banned in the chat
//@status Status of the member in the chat
chatMember member_id:MessageSender inviter_user_id:int53 joined_chat_date:int32 status:ChatMemberStatus = ChatMember;
@ -774,13 +778,14 @@ supergroup id:int53 usernames:usernames date:int32 status:ChatMemberStatus membe
//@can_set_location True, if the supergroup location can be changed
//@can_get_statistics True, if the supergroup or channel statistics are available
//@is_all_history_available True, if new chat members will have access to old messages. In public, discussion, of forum groups and all channels, old messages are always available, so this option affects only private non-forum supergroups without a linked chat. The value of this field is only available for chat administrators
//@is_aggressive_anti_spam_enabled True, if aggressive anti-spam checks are enabled in the supergroup. The value of this field is only available for chat administrators
//@sticker_set_id Identifier of the supergroup sticker set; 0 if none
//@location Location to which the supergroup is connected; may be null
//@invite_link Primary invite link for the chat; may be null. For chat administrators with can_invite_users right only
//@bot_commands List of commands of bots in the group
//@upgraded_from_basic_group_id Identifier of the basic group from which supergroup was upgraded; 0 if none
//@upgraded_from_max_message_id Identifier of the last message in the basic group from which supergroup was upgraded; 0 if none
supergroupFullInfo photo:chatPhoto description:string member_count:int32 administrator_count:int32 restricted_count:int32 banned_count:int32 linked_chat_id:int53 slow_mode_delay:int32 slow_mode_delay_expires_in:double can_get_members:Bool can_set_username:Bool can_set_sticker_set:Bool can_set_location:Bool can_get_statistics:Bool is_all_history_available:Bool sticker_set_id:int64 location:chatLocation invite_link:chatInviteLink bot_commands:vector<botCommands> upgraded_from_basic_group_id:int53 upgraded_from_max_message_id:int53 = SupergroupFullInfo;
supergroupFullInfo photo:chatPhoto description:string member_count:int32 administrator_count:int32 restricted_count:int32 banned_count:int32 linked_chat_id:int53 slow_mode_delay:int32 slow_mode_delay_expires_in:double can_get_members:Bool can_set_username:Bool can_set_sticker_set:Bool can_set_location:Bool can_get_statistics:Bool is_all_history_available:Bool is_aggressive_anti_spam_enabled:Bool sticker_set_id:int64 location:chatLocation invite_link:chatInviteLink bot_commands:vector<botCommands> upgraded_from_basic_group_id:int53 upgraded_from_max_message_id:int53 = SupergroupFullInfo;
//@class SecretChatState @description Describes the current secret chat state
@ -1014,12 +1019,12 @@ notificationSettingsScopeGroupChats = NotificationSettingsScope;
notificationSettingsScopeChannelChats = NotificationSettingsScope;
//@description Contains information about notification settings for a chat
//@use_default_mute_for If true, mute_for is ignored and the value for the relevant type of chat is used instead @mute_for Time left before notifications will be unmuted, in seconds
//@use_default_sound If true, the value for the relevant type of chat is used instead of sound_id @sound_id Identifier of the notification sound to be played; 0 if sound is disabled
//@use_default_show_preview If true, show_preview is ignored and the value for the relevant type of chat is used instead @show_preview True, if message content must be displayed in notifications
//@use_default_disable_pinned_message_notifications If true, disable_pinned_message_notifications is ignored and the value for the relevant type of chat is used instead @disable_pinned_message_notifications If true, notifications for incoming pinned messages will be created as for an ordinary unread message
//@use_default_disable_mention_notifications If true, disable_mention_notifications is ignored and the value for the relevant type of chat is used instead @disable_mention_notifications If true, notifications for messages with mentions will be created as for an ordinary unread message
//@description Contains information about notification settings for a chat or a froum topic
//@use_default_mute_for If true, mute_for is ignored and the value for the relevant type of chat or the forum chat is used instead @mute_for Time left before notifications will be unmuted, in seconds
//@use_default_sound If true, the value for the relevant type of chat or the forum chat is used instead of sound_id @sound_id Identifier of the notification sound to be played; 0 if sound is disabled
//@use_default_show_preview If true, show_preview is ignored and the value for the relevant type of chat or the forum chat is used instead @show_preview True, if message content must be displayed in notifications
//@use_default_disable_pinned_message_notifications If true, disable_pinned_message_notifications is ignored and the value for the relevant type of chat or the forum chat is used instead @disable_pinned_message_notifications If true, notifications for incoming pinned messages will be created as for an ordinary unread message
//@use_default_disable_mention_notifications If true, disable_mention_notifications is ignored and the value for the relevant type of chat or the forum chat is used instead @disable_mention_notifications If true, notifications for messages with mentions will be created as for an ordinary unread message
chatNotificationSettings use_default_mute_for:Bool mute_for:int32 use_default_sound:Bool sound_id:int64 use_default_show_preview:Bool show_preview:Bool use_default_disable_pinned_message_notifications:Bool disable_pinned_message_notifications:Bool use_default_disable_mention_notifications:Bool disable_mention_notifications:Bool = ChatNotificationSettings;
//@description Contains information about notification settings for several chats
@ -1057,9 +1062,9 @@ chatTypeSecret secret_chat_id:int32 user_id:int53 = ChatType;
//@title The title of the filter; 1-12 characters without line feeds
//@icon_name The chosen icon name for short filter representation. If non-empty, must be one of "All", "Unread", "Unmuted", "Bots", "Channels", "Groups", "Private", "Custom", "Setup", "Cat", "Crown", "Favorite", "Flower", "Game", "Home", "Love", "Mask", "Party", "Sport", "Study", "Trade", "Travel", "Work", "Airplane", "Book", "Light", "Like", "Money", "Note", "Palette".
//-If empty, use getChatFilterDefaultIconName to get default icon name for the filter
//@pinned_chat_ids The chat identifiers of pinned chats in the filtered chat list. There can be up to GetOption("chat_filter_chosen_chat_count_max") pinned and always included non-secret chats and the same number of secret chats, but the limit can be increased with Telegram Premium
//@included_chat_ids The chat identifiers of always included chats in the filtered chat list. There can be up to GetOption("chat_filter_chosen_chat_count_max") pinned and always included non-secret chats and the same number of secret chats, but the limit can be increased with Telegram Premium
//@excluded_chat_ids The chat identifiers of always excluded chats in the filtered chat list. There can be up to GetOption("chat_filter_chosen_chat_count_max") always excluded non-secret chats and the same number of secret chats, but the limit can be increased with Telegram Premium
//@pinned_chat_ids The chat identifiers of pinned chats in the filtered chat list. There can be up to getOption("chat_filter_chosen_chat_count_max") pinned and always included non-secret chats and the same number of secret chats, but the limit can be increased with Telegram Premium
//@included_chat_ids The chat identifiers of always included chats in the filtered chat list. There can be up to getOption("chat_filter_chosen_chat_count_max") pinned and always included non-secret chats and the same number of secret chats, but the limit can be increased with Telegram Premium
//@excluded_chat_ids The chat identifiers of always excluded chats in the filtered chat list. There can be up to getOption("chat_filter_chosen_chat_count_max") always excluded non-secret chats and the same number of secret chats, but the limit can be increased with Telegram Premium
//@exclude_muted True, if muted chats need to be excluded
//@exclude_read True, if read chats need to be excluded
//@exclude_archived True, if archived chats need to be excluded
@ -1273,7 +1278,7 @@ inlineKeyboardButton text:string type:InlineKeyboardButtonType = InlineKeyboardB
//@class ReplyMarkup @description Contains a description of a custom keyboard and actions that can be done with it to quickly reply to bots
//@description Instructs application to remove the keyboard once this message has been received. This kind of keyboard can't be received in an incoming message; instead, UpdateChatReplyMarkup with message_id == 0 will be sent
//@description Instructs application to remove the keyboard once this message has been received. This kind of keyboard can't be received in an incoming message; instead, updateChatReplyMarkup with message_id == 0 will be sent
//@is_personal True, if the keyboard is removed only for the mentioned users or the target user of a reply
replyMarkupRemoveKeyboard is_personal:Bool = ReplyMarkup;
@ -1328,13 +1333,15 @@ forumTopicIcon color:int32 custom_emoji_id:int64 = ForumTopicIcon;
//@icon Icon of the topic
//@creation_date Date the topic was created
//@creator_id Identifier of the creator of the topic
//@is_general True, if the topic is the General topic list
//@is_outgoing True, if the topic was created by the current user
//@is_closed True, if the topic is closed
forumTopicInfo message_thread_id:int53 name:string icon:forumTopicIcon creation_date:int32 creator_id:MessageSender is_outgoing:Bool is_closed:Bool = ForumTopicInfo;
//@is_hidden True, if the topic is hidden above the topic list and closed; for General topic only
forumTopicInfo message_thread_id:int53 name:string icon:forumTopicIcon creation_date:int32 creator_id:MessageSender is_general:Bool is_outgoing:Bool is_closed:Bool is_hidden:Bool = ForumTopicInfo;
//@description Describes a forum topic
//@info Basic information about the topic
//@last_message Last message in the topic; may be null
//@last_message Last message in the topic; may be null if unknown
//@is_pinned True, if the topic is pinned in the topic list
//@unread_count Number of unread messages in the topic
//@last_read_inbox_message_id Identifier of the last read incoming message
@ -1345,6 +1352,14 @@ forumTopicInfo message_thread_id:int53 name:string icon:forumTopicIcon creation_
//@draft_message A draft of a message in the topic; may be null
forumTopic info:forumTopicInfo last_message:message is_pinned:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 unread_reaction_count:int32 notification_settings:chatNotificationSettings draft_message:draftMessage = ForumTopic;
//@description Describes a list of forum topics
//@total_count Approximate total number of forum topics found
//@topics List of forum topics
//@next_offset_date Offset date for the next getForumTopics request
//@next_offset_message_id Offset message identifier for the next getForumTopics request
//@next_offset_message_thread_id Offset message thread identifier for the next getForumTopics request
forumTopics total_count:int32 topics:vector<forumTopic> next_offset_date:int32 next_offset_message_id:int53 next_offset_message_thread_id:int53 = ForumTopics;
//@class RichText @description Describes a text object inside an instant-view web page
@ -2104,8 +2119,8 @@ messageScreenshotTaken = MessageContent;
//@description A theme in the chat has been changed @theme_name If non-empty, name of a new theme, set for the chat. Otherwise chat theme was reset to the default one
messageChatSetTheme theme_name:string = MessageContent;
//@description The TTL (Time To Live) setting for messages in the chat has been changed @ttl New message TTL
messageChatSetTtl ttl:int32 = MessageContent;
//@description The TTL (Time To Live) setting for messages in the chat has been changed @ttl New message TTL @from_user_id If not 0, a user identifier, which default setting was automatically applied
messageChatSetTtl ttl:int32 from_user_id:int53 = MessageContent;
//@description A forum topic has been created @name Name of the topic @icon Icon of the topic
messageForumTopicCreated name:string icon:forumTopicIcon = MessageContent;
@ -2113,9 +2128,12 @@ messageForumTopicCreated name:string icon:forumTopicIcon = MessageContent;
//@description A forum topic has been edited @name If non-empty, the new name of the topic @edit_icon_custom_emoji_id True, if icon's custom_emoji_id is changed @icon_custom_emoji_id New unique identifier of the custom emoji shown on the topic icon; 0 if none. Must be ignored if edit_icon_custom_emoji_id is false
messageForumTopicEdited name:string edit_icon_custom_emoji_id:Bool icon_custom_emoji_id:int64 = MessageContent;
//@description A forum topic has been closed or opened @is_closed True if the topic was closed or reopened
//@description A forum topic has been closed or opened @is_closed True, if the topic was closed, otherwise the topic was reopened
messageForumTopicIsClosedToggled is_closed:Bool = MessageContent;
//@description A General forum topic has been hidden or unhidden @is_hidden True, if the topic was hidden, otherwise the topic was unhidden
messageForumTopicIsHiddenToggled is_hidden:Bool = MessageContent;
//@description A non-standard action has happened in the chat @text Message text to be shown in the chat
messageCustomServiceAction text:string = MessageContent;
@ -2258,22 +2276,22 @@ messageCopyOptions send_copy:Bool replace_caption:Bool new_caption:formattedText
//@class InputMessageContent @description The content of a message to send
//@description A text message @text Formatted text to be sent; 1-GetOption("message_text_length_max") characters. Only Bold, Italic, Underline, Strikethrough, Spoiler, CustomEmoji, Code, Pre, PreCode, TextUrl and MentionName entities are allowed to be specified manually
//@description A text message @text Formatted text to be sent; 1-getOption("message_text_length_max") characters. Only Bold, Italic, Underline, Strikethrough, Spoiler, CustomEmoji, Code, Pre, PreCode, TextUrl and MentionName entities are allowed to be specified manually
//@disable_web_page_preview True, if rich web page previews for URLs in the message text must be disabled @clear_draft True, if a chat message draft must be deleted
inputMessageText text:formattedText disable_web_page_preview:Bool clear_draft:Bool = InputMessageContent;
//@description An animation message (GIF-style). @animation Animation file to be sent @thumbnail Animation thumbnail; pass null to skip thumbnail uploading @added_sticker_file_ids File identifiers of the stickers added to the animation, if applicable
//@duration Duration of the animation, in seconds @width Width of the animation; may be replaced by the server @height Height of the animation; may be replaced by the server @caption Animation caption; pass null to use an empty caption; 0-GetOption("message_caption_length_max") characters
//@duration Duration of the animation, in seconds @width Width of the animation; may be replaced by the server @height Height of the animation; may be replaced by the server @caption Animation caption; pass null to use an empty caption; 0-getOption("message_caption_length_max") characters
inputMessageAnimation animation:InputFile thumbnail:inputThumbnail added_sticker_file_ids:vector<int32> duration:int32 width:int32 height:int32 caption:formattedText = InputMessageContent;
//@description An audio message @audio Audio file to be sent @album_cover_thumbnail Thumbnail of the cover for the album; pass null to skip thumbnail uploading @duration Duration of the audio, in seconds; may be replaced by the server @title Title of the audio; 0-64 characters; may be replaced by the server
//@performer Performer of the audio; 0-64 characters, may be replaced by the server @caption Audio caption; pass null to use an empty caption; 0-GetOption("message_caption_length_max") characters
//@performer Performer of the audio; 0-64 characters, may be replaced by the server @caption Audio caption; pass null to use an empty caption; 0-getOption("message_caption_length_max") characters
inputMessageAudio audio:InputFile album_cover_thumbnail:inputThumbnail duration:int32 title:string performer:string caption:formattedText = InputMessageContent;
//@description A document message (general file) @document Document to be sent @thumbnail Document thumbnail; pass null to skip thumbnail uploading @disable_content_type_detection If true, automatic file type detection will be disabled and the document will always be sent as file. Always true for files sent to secret chats @caption Document caption; pass null to use an empty caption; 0-GetOption("message_caption_length_max") characters
//@description A document message (general file) @document Document to be sent @thumbnail Document thumbnail; pass null to skip thumbnail uploading @disable_content_type_detection If true, automatic file type detection will be disabled and the document will always be sent as file. Always true for files sent to secret chats @caption Document caption; pass null to use an empty caption; 0-getOption("message_caption_length_max") characters
inputMessageDocument document:InputFile thumbnail:inputThumbnail disable_content_type_detection:Bool caption:formattedText = InputMessageContent;
//@description A photo message @photo Photo to send. The photo must be at most 10 MB in size. The photo's width and height must not exceed 10000 in total. Width and height ratio must be at most 20 @thumbnail Photo thumbnail to be sent; pass null to skip thumbnail uploading. The thumbnail is sent to the other party only in secret chats @added_sticker_file_ids File identifiers of the stickers added to the photo, if applicable @width Photo width @height Photo height @caption Photo caption; pass null to use an empty caption; 0-GetOption("message_caption_length_max") characters
//@description A photo message @photo Photo to send. The photo must be at most 10 MB in size. The photo's width and height must not exceed 10000 in total. Width and height ratio must be at most 20 @thumbnail Photo thumbnail to be sent; pass null to skip thumbnail uploading. The thumbnail is sent to the other party only in secret chats @added_sticker_file_ids File identifiers of the stickers added to the photo, if applicable @width Photo width @height Photo height @caption Photo caption; pass null to use an empty caption; 0-getOption("message_caption_length_max") characters
//@ttl Photo TTL (Time To Live), in seconds (0-60). A non-zero TTL can be specified only in private chats
inputMessagePhoto photo:InputFile thumbnail:inputThumbnail added_sticker_file_ids:vector<int32> width:int32 height:int32 caption:formattedText ttl:int32 = InputMessageContent;
@ -2282,13 +2300,13 @@ inputMessageSticker sticker:InputFile thumbnail:inputThumbnail width:int32 heigh
//@description A video message @video Video to be sent @thumbnail Video thumbnail; pass null to skip thumbnail uploading @added_sticker_file_ids File identifiers of the stickers added to the video, if applicable
//@duration Duration of the video, in seconds @width Video width @height Video height @supports_streaming True, if the video is supposed to be streamed
//@caption Video caption; pass null to use an empty caption; 0-GetOption("message_caption_length_max") characters @ttl Video TTL (Time To Live), in seconds (0-60). A non-zero TTL can be specified only in private chats
//@caption Video caption; pass null to use an empty caption; 0-getOption("message_caption_length_max") characters @ttl Video TTL (Time To Live), in seconds (0-60). A non-zero TTL can be specified only in private chats
inputMessageVideo video:InputFile thumbnail:inputThumbnail added_sticker_file_ids:vector<int32> duration:int32 width:int32 height:int32 supports_streaming:Bool caption:formattedText ttl:int32 = InputMessageContent;
//@description A video note message @video_note Video note to be sent @thumbnail Video thumbnail; pass null to skip thumbnail uploading @duration Duration of the video, in seconds @length Video width and height; must be positive and not greater than 640
inputMessageVideoNote video_note:InputFile thumbnail:inputThumbnail duration:int32 length:int32 = InputMessageContent;
//@description A voice note message @voice_note Voice note to be sent @duration Duration of the voice note, in seconds @waveform Waveform representation of the voice note in 5-bit format @caption Voice note caption; pass null to use an empty caption; 0-GetOption("message_caption_length_max") characters
//@description A voice note message @voice_note Voice note to be sent @duration Duration of the voice note, in seconds @waveform Waveform representation of the voice note in 5-bit format @caption Voice note caption; pass null to use an empty caption; 0-getOption("message_caption_length_max") characters
inputMessageVoiceNote voice_note:InputFile duration:int32 waveform:bytes caption:formattedText = InputMessageContent;
//@description A message with a location @location Location to be sent @live_period Period for which the location can be updated, in seconds; must be between 60 and 86400 for a live location and 0 otherwise
@ -2604,7 +2622,7 @@ groupCall id:int32 title:string scheduled_start_date:int32 enabled_start_notific
groupCallVideoSourceGroup semantics:string source_ids:vector<int32> = GroupCallVideoSourceGroup;
//@description Contains information about a group call participant's video channel @source_groups List of synchronization source groups of the video @endpoint_id Video channel endpoint identifier
//@is_paused True if the video is paused. This flag needs to be ignored, if new video frames are received
//@is_paused True, if the video is paused. This flag needs to be ignored, if new video frames are received
groupCallParticipantVideoInfo source_groups:vector<groupCallVideoSourceGroup> endpoint_id:string is_paused:Bool = GroupCallParticipantVideoInfo;
//@description Represents a group call participant
@ -2720,7 +2738,7 @@ diceStickersRegular sticker:sticker = DiceStickers;
diceStickersSlotMachine background:sticker lever:sticker left_reel:sticker center_reel:sticker right_reel:sticker = DiceStickers;
//@description Represents the result of an ImportContacts request @user_ids User identifiers of the imported contacts in the same order as they were specified in the request; 0 if the contact is not yet a registered user
//@description Represents the result of an importContacts request @user_ids User identifiers of the imported contacts in the same order as they were specified in the request; 0 if the contact is not yet a registered user
//@importer_count The number of users that imported the corresponding contact; 0 for already registered users or if unavailable
importedContacts user_ids:vector<int53> importer_count:vector<int32> = ImportedContacts;
@ -2767,6 +2785,10 @@ sentWebAppMessage inline_message_id:string = SentWebAppMessage;
httpUrl url:string = HttpUrl;
//@description Contains an HTTPS URL, which can be used to get information about a user @url The URL @expires_in Left time for which the link is valid, in seconds; 0 if the link is a public username link
userLink url:string expires_in:int32 = UserLink;
//@class InputInlineQueryResult @description Represents a single result of an inline query; for bots only
//@description Represents a link to an animated GIF or an animated (i.e., without sound) H.264/MPEG-4 AVC video
@ -2919,8 +2941,8 @@ gameHighScores scores:vector<gameHighScore> = GameHighScores;
//@description A message was edited @old_message The original message before the edit @new_message The message after it was edited
chatEventMessageEdited old_message:message new_message:message = ChatEventAction;
//@description A message was deleted @message Deleted message
chatEventMessageDeleted message:message = ChatEventAction;
//@description A message was deleted @message Deleted message @can_report_anti_spam_false_positive True, if the message deletion can be reported via reportSupergroupAntiSpamFalsePositive
chatEventMessageDeleted message:message can_report_anti_spam_false_positive:Bool = ChatEventAction;
//@description A message was pinned @message Pinned message
chatEventMessagePinned message:message = ChatEventAction;
@ -2997,6 +3019,9 @@ chatEventInvitesToggled can_invite_users:Bool = ChatEventAction;
//@description The is_all_history_available setting of a supergroup was toggled @is_all_history_available New value of is_all_history_available
chatEventIsAllHistoryAvailableToggled is_all_history_available:Bool = ChatEventAction;
//@description The is_aggressive_anti_spam_enabled setting of a supergroup was toggled @is_aggressive_anti_spam_enabled New value of is_aggressive_anti_spam_enabled
chatEventIsAggressiveAntiSpamEnabledToggled is_aggressive_anti_spam_enabled:Bool = ChatEventAction;
//@description The sign_messages setting of a channel was toggled @sign_messages New value of sign_messages
chatEventSignMessagesToggled sign_messages:Bool = ChatEventAction;
@ -3036,6 +3061,9 @@ chatEventForumTopicEdited old_topic_info:forumTopicInfo new_topic_info:forumTopi
//@description A forum topic was closed or reopened @topic_info New information about the topic
chatEventForumTopicToggleIsClosed topic_info:forumTopicInfo = ChatEventAction;
//@description The General forum topic was hidden or unhidden @topic_info New information about the topic
chatEventForumTopicToggleIsHidden topic_info:forumTopicInfo = ChatEventAction;
//@description A forum topic was deleted @topic_info Information about the topic
chatEventForumTopicDeleted topic_info:forumTopicInfo = ChatEventAction;
@ -3360,8 +3388,11 @@ checkChatUsernameResultUsernameInvalid = CheckChatUsernameResult;
//@description The username is occupied
checkChatUsernameResultUsernameOccupied = CheckChatUsernameResult;
//@description The username can be purchased at fragment.com
checkChatUsernameResultUsernamePurchasable = CheckChatUsernameResult;
//@description The user has too many chats with username, one of them must be made private first
checkChatUsernameResultPublicChatsTooMuch = CheckChatUsernameResult;
checkChatUsernameResultPublicChatsTooMany = CheckChatUsernameResult;
//@description The user can't be a member of a public supergroup
checkChatUsernameResultPublicGroupsUnavailable = CheckChatUsernameResult;
@ -3656,6 +3687,10 @@ userPrivacySettingAllowPrivateVoiceAndVideoNoteMessages = UserPrivacySetting;
accountTtl days:int32 = AccountTtl;
//@description Contains default message Time To Live setting (self-destruct timer) for new chats @ttl Message TTL setting, in seconds. If 0, then messages aren't deleted automatically
messageTtl ttl:int32 = MessageTtl;
//@class SessionType @description Represents the type of a session
//@description The session is running on an Android device
@ -3857,7 +3892,7 @@ internalLinkTypeLanguagePack language_pack_id:string = InternalLinkType;
//@description The link is a link to the language settings section of the app
internalLinkTypeLanguageSettings = InternalLinkType;
//@description The link is a link to a Telegram message. Call getMessageLinkInfo with the given URL to process the link @url URL to be passed to getMessageLinkInfo
//@description The link is a link to a Telegram message or a forum topic. Call getMessageLinkInfo with the given URL to process the link @url URL to be passed to getMessageLinkInfo
internalLinkTypeMessage url:string = InternalLinkType;
//@description The link contains a message draft text. A share screen needs to be shown to the user, then the chosen chat must be opened and the text is added to the input field
@ -3914,6 +3949,9 @@ internalLinkTypeUnsupportedProxy = InternalLinkType;
//@description The link is a link to a user by its phone number. Call searchUserByPhoneNumber with the given phone number to process the link @phone_number Phone number of the user
internalLinkTypeUserPhoneNumber phone_number:string = InternalLinkType;
//@description The link is a link to a user by a temporary token. Call searchUserByToken with the given token to process the link @token The token
internalLinkTypeUserToken token:string = InternalLinkType;
//@description The link is a link to a video chat. Call searchPublicChat with the given chat username, and then joinGroupCall with the given invite hash to process the link
//@chat_username Username of the chat with the video chat @invite_hash If non-empty, invite hash to be used to join the video chat without being muted by administrators
//@is_live_stream True, if the video chat is expected to be a live stream in a channel or a broadcast group
@ -3923,10 +3961,10 @@ internalLinkTypeVideoChat chat_username:string invite_hash:string is_live_stream
//@description Contains an HTTPS link to a message in a supergroup or channel @link Message link @is_public True, if the link will work for non-members of the chat
messageLink link:string is_public:Bool = MessageLink;
//@description Contains information about a link to a message in a chat
//@description Contains information about a link to a message or a forum topic in a chat
//@is_public True, if the link is a public link for a message in a chat
//@chat_id If found, identifier of the chat to which the message belongs, 0 otherwise
//@message_thread_id If found, identifier of the message thread in which to open the message, or which to open in case of a missing message
//@message_thread_id If found, identifier of the message thread in which to open the message, or a forum topic to open if the message is missing
//@message If found, the linked message; may be null
//@media_timestamp Timestamp from which the video/audio/video note/voice note playing must start, in seconds; 0 if not specified. The media can be in the message content or in its web page preview
//@for_album True, if the whole media album to which the message belongs is linked
@ -4169,7 +4207,7 @@ fileDownloadedPrefixSize size:int53 = FileDownloadedPrefixSize;
deepLinkInfo text:formattedText need_update_application:Bool = DeepLinkInfo;
//@class TextParseMode @description Describes the way the text needs to be parsed for TextEntities
//@class TextParseMode @description Describes the way the text needs to be parsed for text entities
//@description The text uses Markdown-style formatting
//@version Version of the parser: 0 or 1 - Telegram Bot API "Markdown" parse mode, 2 - Telegram Bot API "MarkdownV2" parse mode
@ -4644,7 +4682,7 @@ updateDiceEmojis emojis:vector<string> = Update;
//@chat_id Chat identifier @message_id Message identifier @sticker The animated sticker to be played
updateAnimatedEmojiMessageClicked chat_id:int53 message_id:int53 sticker:sticker = Update;
//@description The parameters of animation search through GetOption("animation_search_bot_username") bot has changed @provider Name of the animation search provider @emojis The new list of emojis suggested for searching
//@description The parameters of animation search through getOption("animation_search_bot_username") bot has changed @provider Name of the animation search provider @emojis The new list of emojis suggested for searching
updateAnimationSearchParameters provider:string emojis:vector<string> = Update;
//@description The list of suggested to the user actions has changed @added_actions Added suggested actions @removed_actions Removed suggested actions
@ -4821,7 +4859,7 @@ destroy = Ok;
confirmQrCodeAuthentication link:string = Session;
//@description Returns all updates needed to restore current TDLib state, i.e. all actual UpdateAuthorizationState/UpdateUser/UpdateNewChat and others. This is especially useful if TDLib is run in a separate process. Can be called before initialization
//@description Returns all updates needed to restore current TDLib state, i.e. all actual updateAuthorizationState/updateUser/updateNewChat and others. This is especially useful if TDLib is run in a separate process. Can be called before initialization
getCurrentState = Updates;
@ -5198,7 +5236,7 @@ sendBotStartMessage bot_user_id:int53 chat_id:int53 parameter:string = Message;
//@options Options to be used to send the message; pass null to use default options
//@query_id Identifier of the inline query
//@result_id Identifier of the inline result
//@hide_via_bot Pass true to hide the bot, via which the message is sent. Can be used only for bots GetOption("animation_search_bot_username"), GetOption("photo_search_bot_username"), and GetOption("venue_search_bot_username")
//@hide_via_bot Pass true to hide the bot, via which the message is sent. Can be used only for bots getOption("animation_search_bot_username"), getOption("photo_search_bot_username"), and getOption("venue_search_bot_username")
sendInlineQueryResultMessage chat_id:int53 message_thread_id:int53 reply_to_message_id:int53 options:messageSendOptions query_id:int64 result_id:string hide_via_bot:Bool = Message;
//@description Forwards previously sent messages. Returns the forwarded messages in the same order as the message identifiers passed in message_ids. If a message can't be forwarded, null will be returned instead of the message
@ -5267,7 +5305,7 @@ editMessageMedia chat_id:int53 message_id:int53 reply_markup:ReplyMarkup input_m
//@chat_id The chat the message belongs to
//@message_id Identifier of the message
//@reply_markup The new message reply markup; pass null if none; for bots only
//@caption New message content caption; 0-GetOption("message_caption_length_max") characters; pass null to remove caption
//@caption New message content caption; 0-getOption("message_caption_length_max") characters; pass null to remove caption
editMessageCaption chat_id:int53 message_id:int53 reply_markup:ReplyMarkup caption:formattedText = Message;
//@description Edits the message reply markup; for bots only. Returns the edited message after the edit is completed on the server side
@ -5299,7 +5337,7 @@ editInlineMessageMedia inline_message_id:string reply_markup:ReplyMarkup input_m
//@description Edits the caption of an inline message sent via a bot; for bots only
//@inline_message_id Inline message identifier
//@reply_markup The new message reply markup; pass null if none
//@caption New message content caption; pass null to remove caption; 0-GetOption("message_caption_length_max") characters
//@caption New message content caption; pass null to remove caption; 0-getOption("message_caption_length_max") characters
editInlineMessageCaption inline_message_id:string reply_markup:ReplyMarkup caption:formattedText = Ok;
//@description Edits the reply markup of an inline message sent via a bot; for bots only
@ -5326,9 +5364,29 @@ createForumTopic chat_id:int53 name:string icon:forumTopicIcon = ForumTopicInfo;
//@description Edits title and icon of a topic in a forum supergroup chat; requires can_manage_topics administrator rights in the supergroup unless the user is creator of the topic
//@chat_id Identifier of the chat
//@message_thread_id Message thread identifier of the forum topic
//@name New name of the topic; 1-128 characters
//@icon_custom_emoji_id Identifier of the new custom emoji for topic icon. Telegram Premium users can use any custom emoji, other users can use only a custom emoji returned by getForumTopicDefaultIcons
editForumTopic chat_id:int53 message_thread_id:int53 name:string icon_custom_emoji_id:int64 = Ok;
//@name New name of the topic; 0-128 characters. If empty, the previous topic name is kept
//@edit_icon_custom_emoji Pass true to edit the icon of the topic. Icon of the General topic can't be edited
//@icon_custom_emoji_id Identifier of the new custom emoji for topic icon; pass 0 to remove the custom emoji. Ignored if edit_icon_custom_emoji is false. Telegram Premium users can use any custom emoji, other users can use only a custom emoji returned by getForumTopicDefaultIcons
editForumTopic chat_id:int53 message_thread_id:int53 name:string edit_icon_custom_emoji:Bool icon_custom_emoji_id:int64 = Ok;
//@description Returns information about a forum topic @chat_id Identifier of the chat @message_thread_id Message thread identifier of the forum topic
getForumTopic chat_id:int53 message_thread_id:int53 = ForumTopic;
//@description Returns an HTTPS link to a topic in a forum chat. This is an offline request @chat_id Identifier of the chat @message_thread_id Message thread identifier of the forum topic
getForumTopicLink chat_id:int53 message_thread_id:int53 = HttpUrl;
//@description Returns found forum topics in a forum chat. This is a temporary method for getting information about topic list from the server
//@chat_id Identifier of the forum chat
//@query Query to search for in the forum topic's name
//@offset_date The date starting from which the results need to be fetched. Use 0 or any date in the future to get results from the last topic
//@offset_message_id The message identifier of the last message in the last found topic, or 0 for the first request
//@offset_message_thread_id The message thread identifier of the last found topic, or 0 for the first request
//@limit The maximum number of forum topics to be returned; up to 100. For optimal performance, the number of returned forum topics is chosen by TDLib and can be smaller than the specified limit
getForumTopics chat_id:int53 query:string offset_date:int32 offset_message_id:int53 offset_message_thread_id:int53 limit:int32 = ForumTopics;
//@description Changes the notification settings of a forum topic
//@chat_id Chat identifier @message_thread_id Message thread identifier of the forum topic @notification_settings New notification settings for the forum topic. If the topic is muted for more than 366 days, it is considered to be muted forever
setForumTopicNotificationSettings chat_id:int53 message_thread_id:int53 notification_settings:chatNotificationSettings = Ok;
//@description Toggles whether a topic is closed in a forum supergroup chat; requires can_manage_topics administrator rights in the supergroup unless the user is creator of the topic
//@chat_id Identifier of the chat
@ -5336,6 +5394,11 @@ editForumTopic chat_id:int53 message_thread_id:int53 name:string icon_custom_emo
//@is_closed Pass true to close the topic; pass false to reopen it
toggleForumTopicIsClosed chat_id:int53 message_thread_id:int53 is_closed:Bool = Ok;
//@description Toggles whether a General topic is hidden in a forum supergroup chat; requires can_manage_topics administrator rights in the supergroup
//@chat_id Identifier of the chat
//@is_hidden Pass true to hide and close the General topic; pass false to unhide it
toggleGeneralForumTopicIsHidden chat_id:int53 is_hidden:Bool = Ok;
//@description Deletes all messages in a forum topic; requires can_delete_messages administrator rights in the supergroup unless the user is creator of the topic, the topic has no messages from other users and has at most 11 messages
//@chat_id Identifier of the chat
//@message_thread_id Message thread identifier of the forum topic
@ -5535,7 +5598,7 @@ getGameHighScores chat_id:int53 message_id:int53 user_id:int53 = GameHighScores;
getInlineGameHighScores inline_message_id:string user_id:int53 = GameHighScores;
//@description Deletes the default reply markup from a chat. Must be called after a one-time keyboard or a ForceReply reply markup has been used. UpdateChatReplyMarkup will be sent if the reply markup is changed
//@description Deletes the default reply markup from a chat. Must be called after a one-time keyboard or a replyMarkupForceReply reply markup has been used. An updateChatReplyMarkup update will be sent if the reply markup is changed
//@chat_id Chat identifier
//@message_id The message identifier of the used keyboard
deleteChatReplyMarkup chat_id:int53 message_id:int53 = Ok;
@ -5600,16 +5663,20 @@ createSupergroupChat supergroup_id:int53 force:Bool = Chat;
//@description Returns an existing chat corresponding to a known secret chat @secret_chat_id Secret chat identifier
createSecretChat secret_chat_id:int32 = Chat;
//@description Creates a new basic group and sends a corresponding messageBasicGroupChatCreate. Returns the newly created chat @user_ids Identifiers of users to be added to the basic group @title Title of the new basic group; 1-128 characters
createNewBasicGroupChat user_ids:vector<int53> title:string = Chat;
//@description Creates a new basic group and sends a corresponding messageBasicGroupChatCreate. Returns the newly created chat
//@user_ids Identifiers of users to be added to the basic group
//@title Title of the new basic group; 1-128 characters
//@message_ttl Message TTL value, in seconds; must be from 0 up to 365 * 86400 and be divisible by 86400. If 0, then messages aren't deleted automatically
createNewBasicGroupChat user_ids:vector<int53> title:string message_ttl:int32 = Chat;
//@description Creates a new supergroup or channel and sends a corresponding messageSupergroupChatCreate. Returns the newly created chat
//@title Title of the new chat; 1-128 characters
//@is_channel Pass true to create a channel chat
//@param_description Chat description; 0-255 characters
//@location Chat location if a location-based supergroup is being created; pass null to create an ordinary supergroup chat
//@message_ttl Message TTL value, in seconds; must be from 0 up to 365 * 86400 and be divisible by 86400. If 0, then messages aren't deleted automatically
//@for_import Pass true to create a supergroup for importing messages using importMessage
createNewSupergroupChat title:string is_channel:Bool description:string location:chatLocation for_import:Bool = Chat;
createNewSupergroupChat title:string is_channel:Bool description:string location:chatLocation message_ttl:int32 for_import:Bool = Chat;
//@description Creates a new secret chat. Returns the newly created chat @user_id Identifier of the target user
createNewSecretChat user_id:int53 = Chat;
@ -5628,7 +5695,7 @@ addChatToList chat_id:int53 chat_list:ChatList = Ok;
//@description Returns information about a chat filter by its identifier @chat_filter_id Chat filter identifier
getChatFilter chat_filter_id:int32 = ChatFilter;
//@description Creates new chat filter. Returns information about the created chat filter. There can be up to GetOption("chat_filter_count_max") chat filters, but the limit can be increased with Telegram Premium @filter Chat filter
//@description Creates new chat filter. Returns information about the created chat filter. There can be up to getOption("chat_filter_count_max") chat filters, but the limit can be increased with Telegram Premium @filter Chat filter
createChatFilter filter:chatFilter = ChatFilterInfo;
//@description Edits existing chat filter. Returns information about the edited chat filter @chat_filter_id Chat filter identifier @filter The edited chat filter
@ -5655,9 +5722,9 @@ setChatTitle chat_id:int53 title:string = Ok;
//@chat_id Chat identifier @photo New chat photo; pass null to delete the chat photo
setChatPhoto chat_id:int53 photo:InputChatPhoto = Ok;
//@description Changes the message TTL in a chat. Requires can_delete_messages administrator right in basic groups, supergroups and channels
//@description Changes the message TTL in a chat. Requires change_info administrator right in basic groups, supergroups and channels
//-Message TTL can't be changed in a chat with the current user (Saved Messages) and the chat 777000 (Telegram).
//@chat_id Chat identifier @ttl New TTL value, in seconds; unless the chat is secret, it must be from 0 up to 365 * 86400 and be divisible by 86400
//@chat_id Chat identifier @ttl New TTL value, in seconds; unless the chat is secret, it must be from 0 up to 365 * 86400 and be divisible by 86400. If 0, then messages aren't deleted automatically
setChatMessageTtl chat_id:int53 ttl:int32 = Ok;
//@description Changes the chat members permissions. Supported only for basic groups and supergroups. Requires can_restrict_members administrator right
@ -5799,7 +5866,7 @@ setScopeNotificationSettings scope:NotificationSettingsScope notification_settin
resetAllNotificationSettings = Ok;
//@description Changes the pinned state of a chat. There can be up to GetOption("pinned_chat_count_max")/GetOption("pinned_archived_chat_count_max") pinned non-secret chats and the same number of secret chats in the main/archive chat list. The limit can be increased with Telegram Premium
//@description Changes the pinned state of a chat. There can be up to getOption("pinned_chat_count_max")/getOption("pinned_archived_chat_count_max") pinned non-secret chats and the same number of secret chats in the main/archive chat list. The limit can be increased with Telegram Premium
//@chat_list Chat list in which to change the pinned state of the chat @chat_id Chat identifier @is_pinned Pass true to pin the chat; pass false to unpin it
toggleChatIsPinned chat_list:ChatList chat_id:int53 is_pinned:Bool = Ok;
@ -6071,7 +6138,7 @@ joinGroupCall group_call_id:int32 participant_id:MessageSender audio_source_id:i
//@payload Group call join payload; received from tgcalls
startGroupCallScreenSharing group_call_id:int32 audio_source_id:int32 payload:string = Text;
//@description Pauses or unpauses screen sharing in a joined group call @group_call_id Group call identifier @is_paused True if screen sharing is paused
//@description Pauses or unpauses screen sharing in a joined group call @group_call_id Group call identifier @is_paused Pass true to pause screen sharing; pass false to unpause it
toggleGroupCallScreenSharingIsPaused group_call_id:int32 is_paused:Bool = Ok;
//@description Ends screen sharing in a joined group call @group_call_id Group call identifier
@ -6327,7 +6394,7 @@ deleteProfilePhoto profile_photo_id:int64 = Ok;
//@description Changes the first and last name of the current user @first_name The new value of the first name for the current user; 1-64 characters @last_name The new value of the optional last name for the current user; 0-64 characters
setName first_name:string last_name:string = Ok;
//@description Changes the bio of the current user @bio The new value of the user bio; 0-GetOption("bio_length_max") characters without line feeds
//@description Changes the bio of the current user @bio The new value of the user bio; 0-getOption("bio_length_max") characters without line feeds
setBio bio:string = Ok;
//@description Changes the editable username of the current user @username The new value of the username. Use an empty string to remove the username. The username can't be completely removed if there is another active or disabled username
@ -6344,7 +6411,7 @@ reorderActiveUsernames usernames:vector<string> = Ok;
//@duration Duration of the status, in seconds; pass 0 to keep the status active until it will be changed manually
setEmojiStatus emoji_status:emojiStatus duration:int32 = Ok;
//@description Changes the location of the current user. Needs to be called if GetOption("is_location_visible") is true and location changes for more than 1 kilometer @location The new location of the user
//@description Changes the location of the current user. Needs to be called if getOption("is_location_visible") is true and location changes for more than 1 kilometer @location The new location of the user
setLocation location:location = Ok;
//@description Changes the phone number of the user and sends an authentication code to the user's new phone number. On success, returns information about the sent code
@ -6358,6 +6425,13 @@ resendChangePhoneNumberCode = AuthenticationCodeInfo;
checkChangePhoneNumberCode code:string = Ok;
//@description Returns an HTTPS link, which can be used to get information about the current user
getUserLink = UserLink;
//@description Searches a user by a token from the user's link @token Token to search for
searchUserByToken token:string = User;
//@description Sets the list of commands supported by the bot for the given user scope and language; for bots only
//@scope The scope to which the commands are relevant; pass null to change commands in the default bot command scope
//@language_code A two-letter ISO 639-1 language code. If empty, the commands will be applied to all users from the given scope, for which language there are no dedicated commands
@ -6445,7 +6519,10 @@ toggleSupergroupJoinByRequest supergroup_id:int53 join_by_request:Bool = Ok;
//@description Toggles whether the message history of a supergroup is available to new members; requires can_change_info administrator right @supergroup_id The identifier of the supergroup @is_all_history_available The new value of is_all_history_available
toggleSupergroupIsAllHistoryAvailable supergroup_id:int53 is_all_history_available:Bool = Ok;
//@description Toggles whether the supergroup is a forum; requires owner privileges in the supergroup @supergroup_id Identifier of the supergroup @is_forum New value of is_forum. A supergroup can be converted to a forum, only if it has at least GetOption("forum_member_count_min") members
//@description Toggles whether aggressive anti-spam checks are enabled in the supergroup; requires can_delete_messages administrator right. Can be called only if the supergroup has at least getOption("aggressive_anti_spam_supergroup_member_count_min") members @supergroup_id The identifier of the supergroup, which isn't a broadcast group @is_aggressive_anti_spam_enabled The new value of is_aggressive_anti_spam_enabled
toggleSupergroupIsAggressiveAntiSpamEnabled supergroup_id:int53 is_aggressive_anti_spam_enabled:Bool = Ok;
//@description Toggles whether the supergroup is a forum; requires owner privileges in the supergroup @supergroup_id Identifier of the supergroup @is_forum New value of is_forum. A supergroup can be converted to a forum, only if it has at least getOption("forum_member_count_min") members
toggleSupergroupIsForum supergroup_id:int53 is_forum:Bool = Ok;
//@description Upgrades supergroup to a broadcast group; requires owner privileges in the supergroup @supergroup_id Identifier of the supergroup
@ -6454,6 +6531,9 @@ toggleSupergroupIsBroadcastGroup supergroup_id:int53 = Ok;
//@description Reports messages in a supergroup as spam; requires administrator rights in the supergroup @supergroup_id Supergroup identifier @message_ids Identifiers of messages to report
reportSupergroupSpam supergroup_id:int53 message_ids:vector<int53> = Ok;
//@description Reports a false deletion of a message by aggressive anti-spam checks; requires administrator rights in the supergroup. Can be called only for messages from chatEventMessageDeleted with can_report_anti_spam_false_positive == true @supergroup_id Supergroup identifier @message_id Identifier of the erroneously deleted message
reportSupergroupAntiSpamFalsePositive supergroup_id:int53 message_id:int53 = Ok;
//@description Returns information about members or banned users in a supergroup or channel. Can be used only if supergroupFullInfo.can_get_members == true; additionally, administrator privileges may be required for some filters @supergroup_id Identifier of the supergroup or channel
//@filter The type of users to return; pass null to use supergroupMembersFilterRecent @offset Number of users to skip @limit The maximum number of users be returned; up to 200
getSupergroupMembers supergroup_id:int53 filter:SupergroupMembersFilter offset:int32 limit:int32 = ChatMembers;
@ -6485,7 +6565,7 @@ validateOrderInfo input_invoice:InputInvoice order_info:orderInfo allow_save:Boo
//@credentials The credentials chosen by user for payment @tip_amount Chosen by the user amount of tip in the smallest units of the currency
sendPaymentForm input_invoice:InputInvoice payment_form_id:int64 order_info_id:string shipping_option_id:string credentials:InputCredentials tip_amount:int53 = PaymentResult;
//@description Returns information about a successful payment @chat_id Chat identifier of the PaymentSuccessful message @message_id Message identifier
//@description Returns information about a successful payment @chat_id Chat identifier of the messagePaymentSuccessful message @message_id Message identifier
getPaymentReceipt chat_id:int53 message_id:int53 = PaymentReceipt;
//@description Returns saved order information. Returns a 404 error if there is no saved order information
@ -6597,6 +6677,13 @@ getAccountTtl = AccountTtl;
deleteAccount reason:string password:string = Ok;
//@description Changes the default message Time To Live setting (self-destruct timer) for new chats @ttl New message TTL; must be from 0 up to 365 * 86400 and be divisible by 86400. If 0, then messages aren't deleted automatically
setDefaultMessageTtl ttl:messageTtl = Ok;
//@description Returns default message Time To Live setting (self-destruct timer) for new chats
getDefaultMessageTtl = MessageTtl;
//@description Removes a chat action bar without any other action @chat_id Chat identifier
removeChatActionBar chat_id:int53 = Ok;

View File

@ -120,7 +120,7 @@ channel#83259464 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.
channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat;
chatFull#c9d31138 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector<long> available_reactions:flags.18?ChatReactions = ChatFull;
channelFull#f2355507 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_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true id:long 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:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long 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.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions = ChatFull;
channelFull#f2355507 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_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true id:long 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:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long 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.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions = ChatFull;
chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant;
chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant;
@ -176,7 +176,7 @@ messageActionContactSignUp#f3f25f76 = MessageAction;
messageActionGeoProximityReached#98e0d697 from_id:Peer to_id:Peer distance:int = MessageAction;
messageActionGroupCall#7a0d7f42 flags:# call:InputGroupCall duration:flags.0?int = MessageAction;
messageActionInviteToGroupCall#502f92f7 call:InputGroupCall users:Vector<long> = MessageAction;
messageActionSetMessagesTTL#aa1afbfd period:int = MessageAction;
messageActionSetMessagesTTL#3c134d7b flags:# period:int auto_setting_from:flags.0?long = MessageAction;
messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction;
messageActionSetChatTheme#aa786345 emoticon:string = MessageAction;
messageActionChatJoinedByRequest#ebbca3cb = MessageAction;
@ -184,9 +184,9 @@ messageActionWebViewDataSentMe#47dd8079 text:string data:string = MessageAction;
messageActionWebViewDataSent#b4c38cb5 text:string = MessageAction;
messageActionGiftPremium#aba0f5c6 currency:string amount:long months:int = MessageAction;
messageActionTopicCreate#d999256 flags:# title:string icon_color:int icon_emoji_id:flags.0?long = MessageAction;
messageActionTopicEdit#b18a431c flags:# title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool = MessageAction;
messageActionTopicEdit#c0944820 flags:# title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = MessageAction;
dialog#a8edd0f5 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 unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int = Dialog;
dialog#d58a08c6 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 unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?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;
@ -257,7 +257,7 @@ messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs;
messages.messages#8c718e87 messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.messagesSlice#3a54685e flags:# inexact:flags.1?true count:int next_rate:flags.0?int offset_id_offset:flags.2?int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.channelMessages#64479808 flags:# inexact:flags.1?true pts:int count:int offset_id_offset:flags.2?int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.channelMessages#c776ba4e flags:# inexact:flags.1?true pts:int count:int offset_id_offset:flags.2?int messages:Vector<Message> topics:Vector<ForumTopic> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.messagesNotModified#74535f21 count:int = messages.Messages;
messages.chats#64ff9fd5 chats:Vector<Chat> = messages.Chats;
@ -392,7 +392,8 @@ updateRecentEmojiStatuses#30f443db = Update;
updateRecentReactions#6f7863f4 = Update;
updateMoveStickerSetToTop#86fccf85 flags:# masks:flags.0?true emojis:flags.1?true stickerset:long = Update;
updateMessageExtendedMedia#5a73a98c peer:Peer msg_id:int extended_media:MessageExtendedMedia = Update;
updateChannelPinnedTopic#f694b0ae flags:# channel_id:long topic_id:flags.0?int = Update;
updateChannelPinnedTopic#192efbe3 flags:# pinned:flags.0?true channel_id:long topic_id:int = Update;
updateChannelPinnedTopics#fe198602 flags:# channel_id:long order:flags.0?Vector<int> = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@ -714,6 +715,7 @@ auth.codeTypeSms#72a3158c = auth.CodeType;
auth.codeTypeCall#741cd3e3 = auth.CodeType;
auth.codeTypeFlashCall#226ccefb = auth.CodeType;
auth.codeTypeMissedCall#d61ad6ee = auth.CodeType;
auth.codeTypeFragmentSms#6ed998c = auth.CodeType;
auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType;
auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType;
@ -722,6 +724,7 @@ auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType;
auth.sentCodeTypeMissedCall#82006484 prefix:string length:int = auth.SentCodeType;
auth.sentCodeTypeEmailCode#5a159841 flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true email_pattern:string length:int next_phone_login_date:flags.2?int = auth.SentCodeType;
auth.sentCodeTypeSetUpEmailRequired#a5491dea flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true = auth.SentCodeType;
auth.sentCodeTypeFragmentSms#d9565c39 url:string length:int = auth.SentCodeType;
messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer;
@ -955,6 +958,7 @@ channelAdminLogEventActionCreateTopic#58707d28 topic:ForumTopic = ChannelAdminLo
channelAdminLogEventActionEditTopic#f06fe208 prev_topic:ForumTopic new_topic:ForumTopic = ChannelAdminLogEventAction;
channelAdminLogEventActionDeleteTopic#ae168909 topic:ForumTopic = ChannelAdminLogEventAction;
channelAdminLogEventActionPinTopic#5d8d353b flags:# prev_topic:flags.0?ForumTopic new_topic:flags.1?ForumTopic = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleAntiSpam#64f36dfc new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
@ -1457,10 +1461,14 @@ stickerKeyword#fcfeb29c document_id:long keyword:Vector<string> = StickerKeyword
username#b4073647 flags:# editable:flags.0?true active:flags.1?true username:string = Username;
forumTopicDeleted#23f109b id:int = ForumTopic;
forumTopic#71701da9 flags:# my:flags.1?true closed:flags.2?true pinned:flags.3?true id:int date:int title:string icon_color:int icon_emoji_id:flags.0?long top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int from_id:Peer notify_settings:PeerNotifySettings draft:flags.4?DraftMessage = ForumTopic;
forumTopic#71701da9 flags:# my:flags.1?true closed:flags.2?true pinned:flags.3?true short:flags.5?true hidden:flags.6?true id:int date:int title:string icon_color:int icon_emoji_id:flags.0?long top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int from_id:Peer notify_settings:PeerNotifySettings draft:flags.4?DraftMessage = ForumTopic;
messages.forumTopics#367617d3 flags:# order_by_create_date:flags.0?true count:int topics:Vector<ForumTopic> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> pts:int = messages.ForumTopics;
defaultHistoryTTL#43b46b20 period:int = DefaultHistoryTTL;
exportedContactToken#41bf109b url:string expires:int = ExportedContactToken;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@ -1490,6 +1498,7 @@ auth.exportLoginToken#b7e085fe api_id:int api_hash:string except_ids:Vector<long
auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken;
auth.acceptLoginToken#e894ad4d token:bytes = Authorization;
auth.checkRecoveryPassword#d36bf79 code:string = Bool;
auth.importWebTokenAuthorization#2db873a9 api_id:int api_hash:string web_auth_token:string = auth.Authorization;
account.registerDevice#ec86017a flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector<long> = Bool;
account.unregisterDevice#6a0d3206 token_type:int token:string other_uids:Vector<long> = Bool;
@ -1599,6 +1608,8 @@ contacts.acceptContact#f831a20f id:InputUser = Updates;
contacts.getLocated#d348bc44 flags:# background:flags.1?true geo_point:InputGeoPoint self_expires:flags.0?int = Updates;
contacts.blockFromReplies#29a8962c flags:# delete_message:flags.0?true delete_history:flags.1?true report_spam:flags.2?true msg_id:int = Updates;
contacts.resolvePhone#8af94344 phone:string = contacts.ResolvedPeer;
contacts.exportContactToken#f8654027 = ExportedContactToken;
contacts.importContactToken#13005788 token:string = User;
messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages;
messages.getDialogs#a0f4cb4f flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.Dialogs;
@ -1621,7 +1632,7 @@ messages.editChatTitle#73783ffd chat_id:long title:string = Updates;
messages.editChatPhoto#35ddd674 chat_id:long photo:InputChatPhoto = Updates;
messages.addChatUser#f24753e3 chat_id:long user_id:InputUser fwd_limit:int = Updates;
messages.deleteChatUser#a2185cab flags:# revoke_history:flags.0?true chat_id:long user_id:InputUser = Updates;
messages.createChat#9cb126e users:Vector<InputUser> title:string = Updates;
messages.createChat#34a818 flags:# users:Vector<InputUser> title:string ttl_period:flags.0?int = Updates;
messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig;
messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat;
messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat;
@ -1777,6 +1788,8 @@ messages.getTopReactions#bb8125ba limit:int hash:long = messages.Reactions;
messages.getRecentReactions#39461db2 limit:int hash:long = messages.Reactions;
messages.clearRecentReactions#9dfeefb4 = Bool;
messages.getExtendedMedia#84f80814 peer:InputPeer id:Vector<int> = Updates;
messages.setDefaultHistoryTTL#9eb51445 period:int = Bool;
messages.getDefaultHistoryTTL#658b7188 = DefaultHistoryTTL;
updates.getState#edd4882a = updates.State;
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
@ -1828,7 +1841,7 @@ channels.getParticipants#77ced9d0 channel:InputChannel filter:ChannelParticipant
channels.getParticipant#a0ab6cc6 channel:InputChannel participant:InputPeer = channels.ChannelParticipant;
channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;
channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull;
channels.createChannel#3d5fb10f flags:# broadcast:flags.0?true megagroup:flags.1?true for_import:flags.3?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string = Updates;
channels.createChannel#91006707 flags:# broadcast:flags.0?true megagroup:flags.1?true for_import:flags.3?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string ttl_period:flags.4?int = Updates;
channels.editAdmin#d33c8902 channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights rank:string = Updates;
channels.editTitle#566decd0 channel:InputChannel title:string = Updates;
channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates;
@ -1868,9 +1881,12 @@ channels.toggleForum#a4298b29 channel:InputChannel enabled:Bool = Updates;
channels.createForumTopic#f40c0224 flags:# channel:InputChannel title:string icon_color:flags.0?int icon_emoji_id:flags.3?long random_id:long send_as:flags.2?InputPeer = Updates;
channels.getForumTopics#de560d1 flags:# channel:InputChannel q:flags.0?string offset_date:int offset_id:int offset_topic:int limit:int = messages.ForumTopics;
channels.getForumTopicsByID#b0831eb9 channel:InputChannel topics:Vector<int> = messages.ForumTopics;
channels.editForumTopic#6c883e2d flags:# channel:InputChannel topic_id:int title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool = Updates;
channels.editForumTopic#f4dfa185 flags:# channel:InputChannel topic_id:int title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = Updates;
channels.updatePinnedForumTopic#6c2d9026 channel:InputChannel topic_id:int pinned:Bool = Updates;
channels.deleteTopicHistory#34435f2d channel:InputChannel top_msg_id:int = messages.AffectedHistory;
channels.reorderPinnedForumTopics#2950a18f flags:# force:flags.0?true channel:InputChannel order:Vector<int> = Updates;
channels.toggleAntiSpam#68f3e4eb channel:InputChannel enabled:Bool = Updates;
channels.reportAntiSpamFalsePositive#a850a693 channel:InputChannel msg_id:int = Bool;
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;

View File

@ -497,33 +497,29 @@ Status SessionConnection::on_slice_packet(const MsgInfo &info, Slice packet) {
return status;
}
auto get_update_description = [&] {
return PSTRING() << "update from " << get_name() << " active for " << (Time::now() - created_at_)
<< " seconds in container " << container_id_ << " from session " << auth_data_->get_session_id()
<< " with message_id " << info.message_id << ", main_message_id = " << main_message_id_
<< ", seq_no = " << info.seq_no << " and original size = " << info.size;
};
// It is an update... I hope.
status = auth_data_->check_update(info.message_id);
auto recheck_status = auth_data_->recheck_update(info.message_id);
if (recheck_status.is_error() && recheck_status.code() == 2) {
LOG(WARNING) << "Receive very old update from " << get_name() << " created in " << (Time::now() - created_at_)
<< " in container " << container_id_ << " from session " << auth_data_->get_session_id()
<< " with message_id " << info.message_id << ", main_message_id = " << main_message_id_
<< ", seq_no = " << info.seq_no << " and original size " << info.size << ": " << status << ' '
<< recheck_status;
LOG(WARNING) << "Receive very old " << get_update_description() << ": " << status << ' ' << recheck_status;
}
if (status.is_error()) {
if (status.code() == 2) {
LOG(WARNING) << "Receive too old update from " << get_name() << " created in " << (Time::now() - created_at_)
<< " in container " << container_id_ << " from session " << auth_data_->get_session_id()
<< " with message_id " << info.message_id << ", main_message_id = " << main_message_id_
<< ", seq_no = " << info.seq_no << " and original size " << info.size << ": " << status;
LOG(WARNING) << "Receive too old " << get_update_description() << ": " << status;
callback_->on_session_failed(Status::Error("Receive too old update"));
return status;
}
VLOG(mtproto) << "Skip update " << info.message_id << " of size " << info.size << " with seq_no " << info.seq_no
<< " from " << get_name() << " created in " << (Time::now() - created_at_) << ": " << status;
VLOG(mtproto) << "Skip " << get_update_description() << ": " << status;
return Status::OK();
} else {
VLOG(mtproto) << "Got update from " << get_name() << " created in " << (Time::now() - created_at_)
<< " in container " << container_id_ << " from session " << auth_data_->get_session_id()
<< " with message_id " << info.message_id << ", main_message_id = " << main_message_id_
<< ", seq_no = " << info.seq_no << " and original size " << info.size;
VLOG(mtproto) << "Receive " << get_update_description();
return callback_->on_update(as_buffer_slice(packet));
}
}

View File

@ -109,6 +109,64 @@ static td_api::object_ptr<td_api::session> convert_authorization_object(
authorization->country_, authorization->region_);
}
class SetDefaultHistoryTtlQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
public:
explicit SetDefaultHistoryTtlQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(int32 account_ttl) {
send_query(G()->net_query_creator().create(telegram_api::messages_setDefaultHistoryTTL(account_ttl), {{"me"}}));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::messages_setDefaultHistoryTTL>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
bool result = result_ptr.move_as_ok();
if (!result) {
return on_error(Status::Error(500, "Internal Server Error: failed to set default message TTL"));
}
promise_.set_value(Unit());
}
void on_error(Status status) final {
promise_.set_error(std::move(status));
}
};
class GetDefaultHistoryTtlQuery final : public Td::ResultHandler {
Promise<int32> promise_;
public:
explicit GetDefaultHistoryTtlQuery(Promise<int32> &&promise) : promise_(std::move(promise)) {
}
void send() {
send_query(G()->net_query_creator().create(telegram_api::messages_getDefaultHistoryTTL()));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::messages_getDefaultHistoryTTL>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for GetDefaultHistoryTtlQuery: " << to_string(ptr);
promise_.set_value(std::move(ptr->period_));
}
void on_error(Status status) final {
promise_.set_error(std::move(status));
}
};
class SetAccountTtlQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
@ -531,6 +589,73 @@ class SetBotBroadcastDefaultAdminRightsQuery final : public Td::ResultHandler {
}
};
class ExportContactTokenQuery final : public Td::ResultHandler {
Promise<td_api::object_ptr<td_api::userLink>> promise_;
public:
explicit ExportContactTokenQuery(Promise<td_api::object_ptr<td_api::userLink>> &&promise)
: promise_(std::move(promise)) {
}
void send() {
send_query(G()->net_query_creator().create(telegram_api::contacts_exportContactToken()));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::contacts_exportContactToken>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for ExportContactTokenQuery: " << to_string(ptr);
promise_.set_value(td_api::make_object<td_api::userLink>(
ptr->url_, td::max(static_cast<int32>(ptr->expires_ - G()->unix_time()), static_cast<int32>(1))));
}
void on_error(Status status) final {
promise_.set_error(std::move(status));
}
};
class ImportContactTokenQuery final : public Td::ResultHandler {
Promise<td_api::object_ptr<td_api::user>> promise_;
public:
explicit ImportContactTokenQuery(Promise<td_api::object_ptr<td_api::user>> &&promise) : promise_(std::move(promise)) {
}
void send(const string &token) {
send_query(G()->net_query_creator().create(telegram_api::contacts_importContactToken(token)));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::contacts_importContactToken>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
auto user = result_ptr.move_as_ok();
LOG(DEBUG) << "Receive result for ImportContactTokenQuery: " << to_string(user);
auto user_id = ContactsManager::get_user_id(user);
td_->contacts_manager_->on_get_user(std::move(user), "ImportContactTokenQuery");
promise_.set_value(td_->contacts_manager_->get_user_object(user_id));
}
void on_error(Status status) final {
promise_.set_error(std::move(status));
}
};
void set_default_message_ttl(Td *td, int32 message_ttl, Promise<Unit> &&promise) {
td->create_handler<SetDefaultHistoryTtlQuery>(std::move(promise))->send(message_ttl);
}
void get_default_message_ttl(Td *td, Promise<int32> &&promise) {
td->create_handler<GetDefaultHistoryTtlQuery>(std::move(promise))->send();
}
void set_account_ttl(Td *td, int32 account_ttl, Promise<Unit> &&promise) {
td->create_handler<SetAccountTtlQuery>(std::move(promise))->send(account_ttl);
}
@ -602,4 +727,12 @@ void set_default_channel_administrator_rights(Td *td, AdministratorRights admini
td->create_handler<SetBotBroadcastDefaultAdminRightsQuery>(std::move(promise))->send(administrator_rights);
}
void export_contact_token(Td *td, Promise<td_api::object_ptr<td_api::userLink>> &&promise) {
td->create_handler<ExportContactTokenQuery>(std::move(promise))->send();
}
void import_contact_token(Td *td, const string &token, Promise<td_api::object_ptr<td_api::user>> &&promise) {
td->create_handler<ImportContactTokenQuery>(std::move(promise))->send(token);
}
} // namespace td

View File

@ -16,6 +16,10 @@ namespace td {
class Td;
void set_default_message_ttl(Td *td, int32 message_ttl, Promise<Unit> &&promise);
void get_default_message_ttl(Td *td, Promise<int32> &&promise);
void set_account_ttl(Td *td, int32 account_ttl, Promise<Unit> &&promise);
void get_account_ttl(Td *td, Promise<int32> &&promise);
@ -46,4 +50,8 @@ void set_default_group_administrator_rights(Td *td, AdministratorRights administ
void set_default_channel_administrator_rights(Td *td, AdministratorRights administrator_rights,
Promise<Unit> &&promise);
void export_contact_token(Td *td, Promise<td_api::object_ptr<td_api::userLink>> &&promise);
void import_contact_token(Td *td, const string &token, Promise<td_api::object_ptr<td_api::user>> &&promise);
} // namespace td

View File

@ -13,6 +13,7 @@
#include "td/telegram/LinkManager.h"
#include "td/telegram/logevent/LogEvent.h"
#include "td/telegram/MessageReaction.h"
#include "td/telegram/misc.h"
#include "td/telegram/net/AuthDataShared.h"
#include "td/telegram/net/ConnectionCreator.h"
#include "td/telegram/net/DcId.h"
@ -782,9 +783,9 @@ class ConfigRecoverer final : public Actor {
}
if (is_connecting_) {
VLOG(config_recoverer) << "Failed to connect for " << Time::now() - connecting_since_;
VLOG(config_recoverer) << "Failed to connect for " << Time::now() - connecting_since_ << " seconds";
} else {
VLOG(config_recoverer) << "Successfully connected in " << Time::now() - connecting_since_;
VLOG(config_recoverer) << "Successfully connected in " << Time::now() - connecting_since_ << " seconds";
}
Timestamp wakeup_timestamp;
@ -1492,14 +1493,16 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
int32 stickers_premium_by_emoji_num = 0;
int32 stickers_normal_by_emoji_per_premium_num = 2;
int32 forum_upgrade_participants_min = 200;
int32 telegram_antispam_group_size_min = 100;
vector<string> fragment_prefixes;
if (config->get_id() == telegram_api::jsonObject::ID) {
for (auto &key_value : static_cast<telegram_api::jsonObject *>(config.get())->value_) {
Slice key = key_value->key_;
telegram_api::JSONValue *value = key_value->value_.get();
if (key == "getfile_experimental_params" || key == "message_animated_emoji_max" ||
key == "stickers_emoji_cache_time" || key == "test" || key == "upload_max_fileparts_default" ||
key == "upload_max_fileparts_premium" || key == "wallet_blockchain_name" || key == "wallet_config" ||
key == "wallet_enabled") {
key == "reactions_in_chat_max" || key == "stickers_emoji_cache_time" || key == "test" ||
key == "upload_max_fileparts_default" || key == "upload_max_fileparts_premium" ||
key == "wallet_blockchain_name" || key == "wallet_config" || key == "wallet_enabled") {
continue;
}
if (key == "ignore_restriction_reasons") {
@ -1848,6 +1851,32 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
forum_upgrade_participants_min = get_json_value_int(std::move(key_value->value_), key);
continue;
}
if (key == "telegram_antispam_user_id") {
auto setting_value = get_json_value_long(std::move(key_value->value_), key);
G()->set_option_integer("anti_spam_bot_user_id", setting_value);
continue;
}
if (key == "telegram_antispam_group_size_min") {
telegram_antispam_group_size_min = get_json_value_int(std::move(key_value->value_), key);
continue;
}
if (key == "fragment_prefixes") {
if (value->get_id() == telegram_api::jsonArray::ID) {
auto prefixes = std::move(static_cast<telegram_api::jsonArray *>(value)->value_);
for (auto &prefix : prefixes) {
auto prefix_text = get_json_value_string(std::move(prefix), key);
clean_phone_number(prefix_text);
if (!prefix_text.empty()) {
fragment_prefixes.push_back(prefix_text);
} else {
LOG(ERROR) << "Receive an invalid Fragment prefix";
}
}
} else {
LOG(ERROR) << "Receive unexpected fragment_prefixes " << to_string(*value);
}
continue;
}
new_values.push_back(std::move(key_value));
}
@ -1896,6 +1925,8 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
options.set_option_string("dice_emojis", implode(dice_emojis, '\x01'));
}
options.set_option_string("fragment_prefixes", implode(fragment_prefixes, ','));
options.set_option_string("emoji_sounds", implode(emoji_sounds, ','));
if (animated_emoji_zoom <= 0 || animated_emoji_zoom > 2.0) {
@ -1934,11 +1965,12 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
} else {
options.set_option_integer("reactions_uniq_max", reactions_uniq_max);
}
if (forum_upgrade_participants_min < 0) {
options.set_option_empty("forum_member_count_min");
} else {
if (forum_upgrade_participants_min >= 0) {
options.set_option_integer("forum_member_count_min", forum_upgrade_participants_min);
}
if (telegram_antispam_group_size_min >= 0) {
options.set_option_integer("aggressive_anti_spam_supergroup_member_count_min", telegram_antispam_group_size_min);
}
bool is_premium = options.get_option_boolean("is_premium");

View File

@ -6,6 +6,7 @@
//
#include "td/telegram/ContactsManager.h"
#include "td/telegram/Account.h"
#include "td/telegram/AnimationsManager.h"
#include "td/telegram/AuthManager.h"
#include "td/telegram/BotMenuButton.h"
@ -1215,6 +1216,58 @@ class TogglePrehistoryHiddenQuery final : public Td::ResultHandler {
}
};
class ToggleAntiSpamQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
ChannelId channel_id_;
bool is_aggressive_anti_spam_enabled_;
public:
explicit ToggleAntiSpamQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(ChannelId channel_id, bool is_aggressive_anti_spam_enabled) {
channel_id_ = channel_id;
is_aggressive_anti_spam_enabled_ = is_aggressive_anti_spam_enabled;
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
CHECK(input_channel != nullptr);
send_query(G()->net_query_creator().create(
telegram_api::channels_toggleAntiSpam(std::move(input_channel), is_aggressive_anti_spam_enabled),
{{channel_id}}));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::channels_toggleAntiSpam>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for ToggleAntiSpamQuery: " << to_string(ptr);
td_->updates_manager_->on_get_updates(
std::move(ptr),
PromiseCreator::lambda(
[actor_id = G()->contacts_manager(), promise = std::move(promise_), channel_id = channel_id_,
is_aggressive_anti_spam_enabled = is_aggressive_anti_spam_enabled_](Unit result) mutable {
send_closure(actor_id, &ContactsManager::on_update_channel_is_aggressive_anti_spam_enabled, channel_id,
is_aggressive_anti_spam_enabled, std::move(promise));
}));
}
void on_error(Status status) final {
if (status.message() == "CHAT_NOT_MODIFIED") {
if (!td_->auth_manager_->is_bot()) {
promise_.set_value(Unit());
return;
}
} else {
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "ToggleAntiSpamQuery");
}
promise_.set_error(std::move(status));
}
};
class ToggleForumQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
ChannelId channel_id_;
@ -1512,7 +1565,7 @@ class ReportChannelSpamQuery final : public Td::ResultHandler {
CHECK(input_peer != nullptr);
send_query(G()->net_query_creator().create(telegram_api::channels_reportSpam(
std::move(input_channel), std::move(input_peer), MessagesManager::get_server_message_ids(message_ids))));
std::move(input_channel), std::move(input_peer), MessageId::get_server_message_ids(message_ids))));
}
void on_result(BufferSlice packet) final {
@ -1535,6 +1588,42 @@ class ReportChannelSpamQuery final : public Td::ResultHandler {
}
};
class ReportChannelAntiSpamFalsePositiveQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
ChannelId channel_id_;
public:
explicit ReportChannelAntiSpamFalsePositiveQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(ChannelId channel_id, MessageId message_id) {
channel_id_ = channel_id;
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
CHECK(input_channel != nullptr);
send_query(G()->net_query_creator().create(telegram_api::channels_reportAntiSpamFalsePositive(
std::move(input_channel), message_id.get_server_message_id().get())));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::channels_reportAntiSpamFalsePositive>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
bool result = result_ptr.move_as_ok();
LOG_IF(INFO, !result) << "Report anti-spam false positive has failed in " << channel_id_;
promise_.set_value(Unit());
}
void on_error(Status status) final {
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "ReportChannelAntiSpamFalsePositiveQuery");
promise_.set_error(std::move(status));
}
};
class DeleteChatQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
@ -3314,7 +3403,7 @@ class GetSupportUserQuery final : public Td::ResultHandler {
LOG(INFO) << "Receive result for GetSupportUserQuery: " << to_string(ptr);
auto user_id = ContactsManager::get_user_id(ptr->user_);
td_->contacts_manager_->on_get_user(std::move(ptr->user_), "GetSupportUserQuery", false);
td_->contacts_manager_->on_get_user(std::move(ptr->user_), "GetSupportUserQuery");
promise_.set_value(std::move(user_id));
}
@ -3625,6 +3714,9 @@ ContactsManager::ContactsManager(Td *td, ActorShared<> parent) : td_(td), parent
td_->option_manager_->set_option_integer("replies_bot_chat_id", DialogId(get_replies_bot_user_id()).get());
td_->option_manager_->set_option_integer("group_anonymous_bot_user_id", get_anonymous_bot_user_id().get());
td_->option_manager_->set_option_integer("channel_bot_user_id", get_channel_bot_user_id().get());
if (!td_->option_manager_->have_option("anti_spam_bot_user_id")) {
td_->option_manager_->set_option_integer("anti_spam_bot_user_id", get_anti_spam_bot_user_id().get());
}
if (G()->parameters().use_chat_info_db) {
auto next_contacts_sync_date_string = G()->td_db()->get_binlog_pmc()->get("next_contacts_sync_date");
@ -3644,6 +3736,8 @@ ContactsManager::ContactsManager(Td *td, ActorShared<> parent) : td_(td), parent
G()->td_db()->get_sqlite_pmc()->erase_by_prefix("us_bot_info", Auto());
}
on_update_fragment_prefixes();
was_online_local_ = to_integer<int32>(G()->td_db()->get_binlog_pmc()->get("my_was_online_local"));
was_online_remote_ = to_integer<int32>(G()->td_db()->get_binlog_pmc()->get("my_was_online_remote"));
if (was_online_local_ >= G()->unix_time_cached() && !td_->is_online()) {
@ -4714,6 +4808,7 @@ void ContactsManager::ChannelFull::store(StorerT &storer) const {
STORE_FLAG(has_invite_link);
STORE_FLAG(has_bot_commands); // 25
STORE_FLAG(can_be_deleted);
STORE_FLAG(is_aggressive_anti_spam_enabled);
END_STORE_FLAGS();
if (has_description) {
store(description, storer);
@ -4817,6 +4912,7 @@ void ContactsManager::ChannelFull::parse(ParserT &parser) {
PARSE_FLAG(has_invite_link);
PARSE_FLAG(has_bot_commands);
PARSE_FLAG(can_be_deleted);
PARSE_FLAG(is_aggressive_anti_spam_enabled);
END_PARSE_FLAGS();
if (has_description) {
parse(description, parser);
@ -5573,6 +5669,10 @@ UserId ContactsManager::get_channel_bot_user_id() {
return UserId(static_cast<int64>(G()->is_test_dc() ? 936174 : 136817688));
}
UserId ContactsManager::get_anti_spam_bot_user_id() {
return UserId(static_cast<int64>(G()->is_test_dc() ? 2200583762ll : 5434988373ll));
}
UserId ContactsManager::add_anonymous_bot_user() {
auto user_id = get_anonymous_bot_user_id();
if (!have_user_force(user_id)) {
@ -5632,7 +5732,8 @@ void ContactsManager::check_dialog_username(DialogId dialog_id, const string &us
if (username.empty()) {
return promise.set_value(CheckDialogUsernameResult::Ok);
}
if (!is_allowed_username(username)) {
if (!is_allowed_username(username) && username.size() != 4) {
return promise.set_value(CheckDialogUsernameResult::Invalid);
}
@ -5643,11 +5744,14 @@ void ContactsManager::check_dialog_username(DialogId dialog_id, const string &us
return promise.set_value(CheckDialogUsernameResult::PublicGroupsUnavailable);
}
if (error.message() == "CHANNELS_ADMIN_PUBLIC_TOO_MUCH") {
return promise.set_value(CheckDialogUsernameResult::PublicDialogsTooMuch);
return promise.set_value(CheckDialogUsernameResult::PublicDialogsTooMany);
}
if (error.message() == "USERNAME_INVALID") {
return promise.set_value(CheckDialogUsernameResult::Invalid);
}
if (error.message() == "USERNAME_PURCHASE_AVAILABLE") {
return promise.set_value(CheckDialogUsernameResult::Purchasable);
}
return promise.set_error(std::move(error));
}
@ -5678,8 +5782,10 @@ td_api::object_ptr<td_api::CheckChatUsernameResult> ContactsManager::get_check_c
return td_api::make_object<td_api::checkChatUsernameResultUsernameInvalid>();
case CheckDialogUsernameResult::Occupied:
return td_api::make_object<td_api::checkChatUsernameResultUsernameOccupied>();
case CheckDialogUsernameResult::PublicDialogsTooMuch:
return td_api::make_object<td_api::checkChatUsernameResultPublicChatsTooMuch>();
case CheckDialogUsernameResult::Purchasable:
return td_api::make_object<td_api::checkChatUsernameResultUsernamePurchasable>();
case CheckDialogUsernameResult::PublicDialogsTooMany:
return td_api::make_object<td_api::checkChatUsernameResultPublicChatsTooMany>();
case CheckDialogUsernameResult::PublicGroupsUnavailable:
return td_api::make_object<td_api::checkChatUsernameResultPublicGroupsUnavailable>();
default:
@ -7235,6 +7341,27 @@ void ContactsManager::toggle_channel_is_all_history_available(ChannelId channel_
td_->create_handler<TogglePrehistoryHiddenQuery>(std::move(promise))->send(channel_id, is_all_history_available);
}
void ContactsManager::toggle_channel_is_aggressive_anti_spam_enabled(ChannelId channel_id,
bool is_aggressive_anti_spam_enabled,
Promise<Unit> &&promise) {
auto c = get_channel(channel_id);
if (c == nullptr) {
return promise.set_error(Status::Error(400, "Supergroup not found"));
}
if (!get_channel_permissions(c).can_delete_messages()) {
return promise.set_error(Status::Error(400, "Not enough rights to enable aggressive anti-spam checks"));
}
if (get_channel_type(c) != ChannelType::Megagroup) {
return promise.set_error(Status::Error(400, "Aggressive anti-spam checks can be enabled in supergroups only"));
}
if (c->is_gigagroup) {
return promise.set_error(
Status::Error(400, "Aggressive anti-spam checks can't be enabled in broadcast supergroups"));
}
td_->create_handler<ToggleAntiSpamQuery>(std::move(promise))->send(channel_id, is_aggressive_anti_spam_enabled);
}
void ContactsManager::toggle_channel_is_forum(ChannelId channel_id, bool is_forum, Promise<Unit> &&promise) {
auto c = get_channel(channel_id);
if (c == nullptr) {
@ -7615,6 +7742,27 @@ void ContactsManager::report_channel_spam(ChannelId channel_id, const vector<Mes
lock_promise.set_value(Unit());
}
void ContactsManager::report_channel_anti_spam_false_positive(ChannelId channel_id, MessageId message_id,
Promise<Unit> &&promise) {
auto c = get_channel(channel_id);
if (c == nullptr) {
return promise.set_error(Status::Error(400, "Supergroup not found"));
}
if (!c->is_megagroup) {
return promise.set_error(Status::Error(400, "The chat is not a supergroup"));
}
if (!c->status.is_administrator()) {
return promise.set_error(
Status::Error(400, "Anti-spam checks false positives can be reported only by chat administrators"));
}
if (!message_id.is_valid() || !message_id.is_server()) {
return promise.set_error(Status::Error(400, "Invalid message identifier specified"));
}
td_->create_handler<ReportChannelAntiSpamFalsePositiveQuery>(std::move(promise))->send(channel_id, message_id);
}
void ContactsManager::delete_chat(ChatId chat_id, Promise<Unit> &&promise) {
auto c = get_chat(chat_id);
if (c == nullptr) {
@ -9643,7 +9791,8 @@ ContactsManager::User *ContactsManager::get_user_force(UserId user_id) {
auto u = get_user_force_impl(user_id);
if ((u == nullptr || !u->is_received) &&
(user_id == get_service_notifications_user_id() || user_id == get_replies_bot_user_id() ||
user_id == get_anonymous_bot_user_id() || user_id == get_channel_bot_user_id())) {
user_id == get_anonymous_bot_user_id() || user_id == get_channel_bot_user_id() ||
user_id == get_anti_spam_bot_user_id())) {
int32 flags = USER_FLAG_HAS_ACCESS_HASH | USER_FLAG_HAS_FIRST_NAME | USER_FLAG_NEED_APPLY_MIN_PHOTO;
int64 profile_photo_id = 0;
int32 profile_photo_dc_id = 1;
@ -9688,6 +9837,17 @@ ContactsManager::User *ContactsManager::get_user_force(UserId user_id) {
username = G()->is_test_dc() ? "channelsbot" : "Channel_Bot";
bot_info_version = G()->is_test_dc() ? 1 : 4;
profile_photo_id = 587627495930570665;
} else if (user_id == get_service_notifications_user_id()) {
flags |= USER_FLAG_HAS_USERNAME | USER_FLAG_IS_BOT;
if (G()->is_test_dc()) {
first_name = "antispambot";
username = "tantispambot";
} else {
flags |= USER_FLAG_IS_VERIFIED;
first_name = "Telegram Anti-Spam";
username = "tgsantispambot";
profile_photo_id = 5170408289966598902;
}
}
telegram_api::object_ptr<telegram_api::userProfilePhoto> profile_photo;
@ -9706,6 +9866,8 @@ ContactsManager::User *ContactsManager::get_user_force(UserId user_id) {
on_get_user(std::move(user), "get_user_force");
u = get_user(user_id);
CHECK(u != nullptr && u->is_received);
reload_user(user_id, Promise<Unit>());
}
return u;
}
@ -10889,13 +11051,14 @@ void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, boo
if (!u->phone_number.empty() && !td_->auth_manager_->is_bot()) {
resolved_phone_numbers_[u->phone_number] = user_id;
}
u->is_fragment_phone_number = is_fragment_phone_number(u->phone_number);
u->is_phone_number_changed = false;
}
if (u->is_status_changed && user_id != get_my_id()) {
auto left_time = get_user_was_online(u, user_id) - G()->server_time_cached();
if (left_time >= 0 && left_time < 30 * 86400) {
left_time += 2.0; // to guarantee expiration
LOG(DEBUG) << "Set online timeout for " << user_id << " in " << left_time;
LOG(DEBUG) << "Set online timeout for " << user_id << " in " << left_time << " seconds";
user_online_timeout_.set_timeout_in(user_id.get(), left_time);
} else {
LOG(DEBUG) << "Cancel online timeout for " << user_id;
@ -10922,7 +11085,7 @@ void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, boo
auto until_date = u->emoji_status.get_until_date();
auto left_time = until_date - unix_time;
if (left_time >= 0 && left_time < 30 * 86400) {
LOG(DEBUG) << "Set emoji status timeout for " << user_id << " in " << left_time;
LOG(DEBUG) << "Set emoji status timeout for " << user_id << " in " << left_time << " seconds";
user_emoji_status_timeout_.set_timeout_in(user_id.get(), left_time);
} else {
user_emoji_status_timeout_.cancel_timeout(user_id.get());
@ -11913,6 +12076,7 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
auto can_set_sticker_set = (channel->flags_ & CHANNEL_FULL_FLAG_CAN_SET_STICKER_SET) != 0;
auto can_set_location = (channel->flags_ & CHANNEL_FULL_FLAG_CAN_SET_LOCATION) != 0;
auto is_all_history_available = (channel->flags_ & CHANNEL_FULL_FLAG_IS_ALL_HISTORY_HIDDEN) == 0;
auto is_aggressive_anti_spam_enabled = channel->antispam_;
auto can_view_statistics = (channel->flags_ & CHANNEL_FULL_FLAG_CAN_VIEW_STATISTICS) != 0;
StickerSetId sticker_set_id;
if (channel->stickerset_ != nullptr) {
@ -11939,7 +12103,8 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
channel_full->can_set_location != can_set_location ||
channel_full->can_view_statistics != can_view_statistics || channel_full->stats_dc_id != stats_dc_id ||
channel_full->sticker_set_id != sticker_set_id ||
channel_full->is_all_history_available != is_all_history_available) {
channel_full->is_all_history_available != is_all_history_available ||
channel_full->is_aggressive_anti_spam_enabled != is_aggressive_anti_spam_enabled) {
channel_full->participant_count = participant_count;
channel_full->administrator_count = administrator_count;
channel_full->restricted_count = restricted_count;
@ -11950,8 +12115,9 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
channel_full->can_set_location = can_set_location;
channel_full->can_view_statistics = can_view_statistics;
channel_full->stats_dc_id = stats_dc_id;
channel_full->is_all_history_available = is_all_history_available;
channel_full->sticker_set_id = sticker_set_id;
channel_full->is_all_history_available = is_all_history_available;
channel_full->is_aggressive_anti_spam_enabled = is_aggressive_anti_spam_enabled;
channel_full->is_changed = true;
}
@ -14926,6 +15092,20 @@ void ContactsManager::on_update_channel_is_all_history_available(ChannelId chann
promise.set_value(Unit());
}
void ContactsManager::on_update_channel_is_aggressive_anti_spam_enabled(ChannelId channel_id,
bool is_aggressive_anti_spam_enabled,
Promise<Unit> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
CHECK(channel_id.is_valid());
auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_is_aggressive_anti_spam_enabled");
if (channel_full != nullptr && channel_full->is_aggressive_anti_spam_enabled != is_aggressive_anti_spam_enabled) {
channel_full->is_aggressive_anti_spam_enabled = is_aggressive_anti_spam_enabled;
channel_full->is_changed = true;
update_channel_full(channel_full, channel_id, "on_update_channel_is_aggressive_anti_spam_enabled");
}
promise.set_value(Unit());
}
void ContactsManager::on_update_channel_default_permissions(ChannelId channel_id,
RestrictedRights default_permissions) {
if (!channel_id.is_valid()) {
@ -15244,6 +15424,31 @@ void ContactsManager::reload_dialog_info(DialogId dialog_id, Promise<Unit> &&pro
}
}
void ContactsManager::get_user_link(Promise<td_api::object_ptr<td_api::userLink>> &&promise) {
get_me(
PromiseCreator::lambda([actor_id = actor_id(this), promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
send_closure(actor_id, &ContactsManager::get_user_link_impl, std::move(promise));
}
}));
}
void ContactsManager::get_user_link_impl(Promise<td_api::object_ptr<td_api::userLink>> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
const auto *u = get_user(get_my_id());
if (u != nullptr && u->usernames.has_first_username()) {
return promise.set_value(
td_api::make_object<td_api::userLink>(LinkManager::get_public_chat_link(u->usernames.get_first_username()), 0));
}
export_contact_token(td_, std::move(promise));
}
void ContactsManager::search_user_by_token(string token, Promise<td_api::object_ptr<td_api::user>> &&promise) {
import_contact_token(td_, token, std::move(promise));
}
void ContactsManager::send_get_me_query(Td *td, Promise<Unit> &&promise) {
vector<tl_object_ptr<telegram_api::InputUser>> users;
users.push_back(make_tl_object<telegram_api::inputUserSelf>());
@ -15268,7 +15473,8 @@ bool ContactsManager::get_user(UserId user_id, int left_tries, Promise<Unit> &&p
}
if (user_id == get_service_notifications_user_id() || user_id == get_replies_bot_user_id() ||
user_id == get_anonymous_bot_user_id() || user_id == get_channel_bot_user_id()) {
user_id == get_anonymous_bot_user_id() || user_id == get_channel_bot_user_id() ||
user_id == get_anti_spam_bot_user_id()) {
get_user_force(user_id);
}
@ -16750,6 +16956,45 @@ void ContactsManager::on_update_channel_administrator_count(ChannelId channel_id
}
}
bool ContactsManager::is_fragment_phone_number(string phone_number) const {
if (phone_number.empty()) {
return false;
}
clean_phone_number(phone_number);
for (auto &prefix : fragment_prefixes_) {
if (begins_with(phone_number, prefix)) {
return true;
}
}
return false;
}
void ContactsManager::on_update_fragment_prefixes() {
if (G()->close_flag()) {
return;
}
if (td_->auth_manager_->is_bot()) {
return;
}
auto fragment_prefixes_str = td_->option_manager_->get_option_string("fragment_prefixes", "888");
if (fragment_prefixes_str == fragment_prefixes_str_) {
return;
}
fragment_prefixes_str_ = std::move(fragment_prefixes_str);
fragment_prefixes_ = full_split(fragment_prefixes_str_, ',');
users_.foreach([&](const UserId &user_id, unique_ptr<User> &user) {
User *u = user.get();
bool should_be_fragment_phone_number = is_fragment_phone_number(u->phone_number);
if (u->is_fragment_phone_number != should_be_fragment_phone_number) {
u->is_fragment_phone_number = should_be_fragment_phone_number;
u->is_changed = true;
update_user(u, user_id);
}
});
}
void ContactsManager::on_update_dialog_administrators(DialogId dialog_id, vector<DialogAdministrator> &&administrators,
bool have_access, bool from_database) {
LOG(INFO) << "Update administrators in " << dialog_id << " to " << format::as_array(administrators);
@ -17416,7 +17661,8 @@ td_api::object_ptr<td_api::UserStatus> ContactsManager::get_user_status_object(U
td_api::object_ptr<td_api::updateUser> ContactsManager::get_update_unknown_user_object(UserId user_id) {
return td_api::make_object<td_api::updateUser>(td_api::make_object<td_api::user>(
user_id.get(), "", "", nullptr, "", td_api::make_object<td_api::userStatusEmpty>(), nullptr, nullptr, false,
false, false, false, false, "", false, false, false, td_api::make_object<td_api::userTypeUnknown>(), "", false));
false, false, false, false, false, "", false, false, false, td_api::make_object<td_api::userTypeUnknown>(), "",
false));
}
int64 ContactsManager::get_user_id_object(UserId user_id, const char *source) const {
@ -17478,8 +17724,8 @@ tl_object_ptr<td_api::user> ContactsManager::get_user_object(UserId user_id, con
user_id.get(), u->first_name, u->last_name, u->usernames.get_usernames_object(), u->phone_number,
get_user_status_object(user_id, u), get_profile_photo_object(td_->file_manager_.get(), u->photo),
std::move(emoji_status), u->is_contact, u->is_mutual_contact, u->is_verified, u->is_premium, u->is_support,
get_restriction_reason_description(u->restriction_reasons), u->is_scam, u->is_fake, u->is_received,
std::move(type), u->language_code, u->attach_menu_enabled);
u->is_fragment_phone_number, get_restriction_reason_description(u->restriction_reasons), u->is_scam, u->is_fake,
u->is_received, std::move(type), u->language_code, u->attach_menu_enabled);
}
vector<int64> ContactsManager::get_user_ids_object(const vector<UserId> &user_ids, const char *source) const {
@ -17658,9 +17904,9 @@ tl_object_ptr<td_api::supergroupFullInfo> ContactsManager::get_supergroup_full_i
channel_full->banned_count, DialogId(channel_full->linked_channel_id).get(), channel_full->slow_mode_delay,
slow_mode_delay_expires_in, channel_full->can_get_participants, channel_full->can_set_username,
channel_full->can_set_sticker_set, channel_full->can_set_location, channel_full->can_view_statistics,
channel_full->is_all_history_available, channel_full->sticker_set_id.get(),
channel_full->location.get_chat_location_object(), channel_full->invite_link.get_chat_invite_link_object(this),
std::move(bot_commands),
channel_full->is_all_history_available, channel_full->is_aggressive_anti_spam_enabled,
channel_full->sticker_set_id.get(), channel_full->location.get_chat_location_object(),
channel_full->invite_link.get_chat_invite_link_object(this), std::move(bot_commands),
get_basic_group_id_object(channel_full->migrated_from_chat_id, "get_supergroup_full_info_object"),
channel_full->migrated_from_max_message_id.get());
}

View File

@ -213,6 +213,8 @@ class ContactsManager final : public Actor {
void on_update_channel_slow_mode_next_send_date(ChannelId channel_id, int32 slow_mode_next_send_date);
void on_update_channel_is_all_history_available(ChannelId channel_id, bool is_all_history_available,
Promise<Unit> &&promise);
void on_update_channel_is_aggressive_anti_spam_enabled(ChannelId channel_id, bool is_aggressive_anti_spam_enabled,
Promise<Unit> &&promise);
void on_update_channel_default_permissions(ChannelId channel_id, RestrictedRights default_permissions);
void on_update_channel_administrator_count(ChannelId channel_id, int32 administrator_count);
@ -233,6 +235,8 @@ class ContactsManager final : public Actor {
void on_update_bot_menu_button(UserId bot_user_id, tl_object_ptr<telegram_api::BotMenuButton> &&bot_menu_button);
void on_update_fragment_prefixes();
void on_update_dialog_administrators(DialogId dialog_id, vector<DialogAdministrator> &&administrators,
bool have_access, bool from_database);
@ -284,6 +288,8 @@ class ContactsManager final : public Actor {
static UserId get_channel_bot_user_id();
static UserId get_anti_spam_bot_user_id();
UserId add_anonymous_bot_user();
UserId add_channel_bot_user();
@ -306,7 +312,14 @@ class ContactsManager final : public Actor {
void invalidate_user_full(UserId user_id);
enum class CheckDialogUsernameResult : uint8 { Ok, Invalid, Occupied, PublicDialogsTooMuch, PublicGroupsUnavailable };
enum class CheckDialogUsernameResult : uint8 {
Ok,
Invalid,
Occupied,
Purchasable,
PublicDialogsTooMany,
PublicGroupsUnavailable
};
void check_dialog_username(DialogId dialog_id, const string &username, Promise<CheckDialogUsernameResult> &&promise);
@ -390,6 +403,9 @@ class ContactsManager final : public Actor {
void toggle_channel_is_all_history_available(ChannelId channel_id, bool is_all_history_available,
Promise<Unit> &&promise);
void toggle_channel_is_aggressive_anti_spam_enabled(ChannelId channel_id, bool is_aggressive_anti_spam_enabled,
Promise<Unit> &&promise);
void toggle_channel_is_forum(ChannelId channel_id, bool is_forum, Promise<Unit> &&promise);
void convert_channel_to_gigagroup(ChannelId channel_id, Promise<Unit> &&promise);
@ -404,6 +420,8 @@ class ContactsManager final : public Actor {
void report_channel_spam(ChannelId channel_id, const vector<MessageId> &message_ids, Promise<Unit> &&promise);
void report_channel_anti_spam_false_positive(ChannelId channel_id, MessageId message_id, Promise<Unit> &&promise);
void delete_dialog(DialogId dialog_id, Promise<Unit> &&promise);
void get_channel_statistics_dc_id(DialogId dialog_id, bool for_full_statistics, Promise<DcId> &&promise);
@ -522,6 +540,10 @@ class ContactsManager final : public Actor {
void reload_dialog_info(DialogId dialog_id, Promise<Unit> &&promise);
void get_user_link(Promise<td_api::object_ptr<td_api::userLink>> &&promise);
void search_user_by_token(string token, Promise<td_api::object_ptr<td_api::user>> &&promise);
static void send_get_me_query(Td *td, Promise<Unit> &&promise);
UserId get_me(Promise<Unit> &&promise);
bool get_user(UserId user_id, int left_tries, Promise<Unit> &&promise);
@ -716,6 +738,7 @@ class ContactsManager final : public Actor {
bool need_apply_min_photo = false;
bool can_be_added_to_attach_menu = false;
bool attach_menu_enabled = false;
bool is_fragment_phone_number = false;
bool is_photo_inited = false;
@ -976,6 +999,7 @@ class ContactsManager final : public Actor {
bool can_view_statistics = false;
bool is_can_view_statistics_inited = false;
bool is_all_history_available = true;
bool is_aggressive_anti_spam_enabled = true;
bool can_be_deleted = false;
bool is_slow_mode_next_send_date_changed = true;
@ -1203,6 +1227,7 @@ class ContactsManager final : public Actor {
static constexpr int32 CHANNEL_FULL_FLAG_HAS_PENDING_REQUEST_COUNT = 1 << 28;
static constexpr int32 CHANNEL_FULL_FLAG_HAS_DEFAULT_SEND_AS = 1 << 29;
static constexpr int32 CHANNEL_FULL_FLAG_HAS_AVAILABLE_REACTIONS = 1 << 30;
static constexpr int32 CHANNEL_FULL_FLAG2_HAS_ANTISPAM = 1 << 1;
static constexpr int32 CHAT_INVITE_FLAG_IS_CHANNEL = 1 << 0;
static constexpr int32 CHAT_INVITE_FLAG_IS_BROADCAST = 1 << 1;
@ -1293,6 +1318,8 @@ class ContactsManager final : public Actor {
string get_channel_search_text(ChannelId channel_id) const;
static string get_channel_search_text(const Channel *c);
void get_user_link_impl(Promise<td_api::object_ptr<td_api::userLink>> &&promise);
void set_my_id(UserId my_id);
static bool is_allowed_username(const string &username);
@ -1488,6 +1515,8 @@ class ContactsManager final : public Actor {
bool is_user_contact(const User *u, UserId user_id, bool is_mutual) const;
bool is_fragment_phone_number(string phone_number) const;
int32 get_user_was_online(const User *u, UserId user_id) const;
int64 get_contacts_hash();
@ -1920,6 +1949,9 @@ class ContactsManager final : public Actor {
vector<UserId> imported_contact_user_ids_; // result of change_imported_contacts
vector<int32> unimported_contact_invites_; // result of change_imported_contacts
string fragment_prefixes_str_;
vector<string> fragment_prefixes_;
MultiTimeout user_online_timeout_{"UserOnlineTimeout"};
MultiTimeout user_emoji_status_timeout_{"UserEmojiStatusTimeout"};
MultiTimeout channel_unban_timeout_{"ChannelUnbanTimeout"};

View File

@ -445,70 +445,70 @@ const CountryInfoManager::CountryList *CountryInfoManager::get_country_list(Coun
if (language_code == "en") {
static const BufferSlice en = gzdecode(
base64url_decode(
"eJyNW0tz48iRrhb1lrpn2h6PfXBMMGIjvN6IHQeJN458iyJBsQlSr1uRrCFrBAIaEJAs_QHf9ifsxQeHD77t_oK27_"
"4Pvvmyl73sbROkSIBEstAR3S01VVmVlZX55ZdZpf8M__6HX_z1v3_9T0LIv_zHHz7DF7JXqpKjkjv2fJ9GP3sHn_"
"3P33LlPfiak3Vt9dnx7W1-8WdDtka-Gbg8YON8yafDfG3GfRqwOfwsNZepF1efnS0mWvy9jeeqk7PSD5Mpdfk8oO62_"
"J4pk4T8eoJYvkE-ltyAT0Ka_02-TP1hOKZpPfaLkmYk9DteKbKxryY5LrmTkDsORfYSzaFkztEGuzpD2A5iV1UV28ICWX_"
"GUFldWX12Gssm1r0ih6C7B5qnZCVFEduwR05K_oSBGd0t2y1-riqJdWzyoTRjPh9RN2_TmZdeb7-oGdl26sNew3ngp_"
"e6p8RnfrqS3djrAPSNZKnDkbPe04oJn1lIb9n5hhyU_HCIyOYkUxfrfU9OS6_MH1L-I3URfzcV4RmXS-SbsjeHIwZ3vWD-K5t4Twuzp-"
"eSDV145uUyOY48no49LPbAXxUt6xzKVXJapu7EoWM2n6Z1MIyCWIcaOSozZ8LDWeocZGk93_ntCki2sKRcJ-fl0H8AE-"
"TrdO5hdpAkbdOmyz_xHA2wQ-hMqM-37UiWcWfGYy9AXzr1KU9hDWCVvPrs5DY2VizbBNnQD90xT-"
"uobp1VftNny5fkoAyR7aL7M8U2tiIb-zNAtvQZK0ox84w75GMZ1GY8X6V-OJ9Th84QPbR4__g8V6CH5_"
"AnBJ9UsxjvYe32CdlP5Luy51Lus3_P29wN8jWIYBrwcA6BYNMhTZ-baibOrUcOyz595U463lV1_dn7FVykzs5enDud0TkWJ1KmDfuw_"
"jQM0JjXVfH53YB_esH8meJxLmkZcX63iLHo6JC8IM4p5XvQmzn8lSH2LRTX4yolclgB_cab55CDr--KS51_"
"G8koBTmnGnpONwo5Q1JzkqyB7xdyWkEB_"
"5Fyum7kJPhekYswv5bTC2bOLMDnhhTFMeQiMycZZk5W5JysqTmlqMFYPacWzZyqGDmtKOc0BeYvqDmjoINsNMaAMfAX1lGLSk7VYaxRz"
"BkgY-gwD6yjyfB9bMfzRJ7bOMdKlXyseJAo87-tstnv8j32-Lt_w85EkYV2rdTJNxXImJCD8qUflukwmgs9X1mMX5UGOX_"
"T6U0dTB9JrM8FObOfeQCpyaHuOJ1TkzkRk2-SD5XP_xWw_Phfm08ehCmGU-pmnOXTcVZpRXvxHvLNeaTHdl5a-"
"J1mSPH4NjmoTLnDkDyuauI8XrHIcYUCGfE8F7f72h9QPK90Fmtvc57F2oaWxJTE6kn5K1jfc7zZMJV3lvrr2_"
"kP8cceOa14gIT5HvhQeg8QQ-I9DMh-ZUFlkPWTPArB5Mo1rE0fWf6a-"
"WPsvGVDiIkVwLVK6NPPf6LbefvdG36vPntnJuXuAGteHgHOEM6jZpzZPfjpKxtNo2gLhw4fpedQpELC19N8twqcpQH5lLov6TgxF_"
"Ptv53ZinxG-z4rauv_nhX1-HtZKxTzStE0kmtckuPqj3zohQFHfVOVhZhQbZGjKnNn1H9I6xjnO9RGVYiLqjfjbuRRGC_"
"UNZ1k5LvqFfmwmuMN2aLxuY15jIK5Y57EGOkLxii7xsT63Ed11YQh9UJOKspbcZbmmbUKOaqNQqDKPsJdxFhfA3-"
"pzQMPr8sk4VnUGuSgNnl5DJD4lApJfEhCTEK-B2v7PPAZsu-Yc53EtCEha5MD-5FinHNPVsR1da1PjmvBlHuPKLaB_4rr-"
"jpw5Tp3t3MRWca4EY-7JPt1_iMaI5puCn2i3iJf16nzEC0iyjdqoRDLWOTU4iPfc9mcI5xTM2NOVL8i7-"
"vU91g8OXIGa4w82rZhHThr3afuKI2te7KcyC_"
"5DaddyzdK5KBBhx5aMyibfPtNOJYtkw9vPZoWdydjb5bWQdn0gRWgxXNUASd9FpFCpO7Q5ayYbSxw1vMnSNyYpir0v0YdbA9rA9A3Qk6"
"xvgTErRKPvwBbTVPj3vKYOL4bTXLS4EOgcgH1sTpcLQhjvNEGeZ-xhbejPmLu9JGGRQ4bdMEgEL5VENu3A7IhdxkqK-"
"75NLrktAFwyBwvfERyv2qu196JqY1P5GPtp5AGHqCyk39TBfNVcT5uQJxE9kPjZAMjcQ7V6IP9QQ02ow62vlqQNmJlmwc1gEOB_"
"AzBoP2ipmfW140b8n65-e_LHKrrELWBKp7jLjrLl8iBET-P-fJFi5xcQK2Qb8E_yDqGKt7rRYccg_"
"wYaBvar1ULitDXLyAfVXwPCnckFxriOviiTw4uKI8IEbKuKV53QI4uQndC_"
"TRnkzUi9K9mlZw03fEb5CP9wrhPhfYbm4BjTZ9hdRVggxhbmm1y2Jz7lKX7FjlTF9d0TahPQG9UZ7O4id1vWseyV-"
"S8yhnUlA3qj3bkcEUT-mTzE9lv-vQnTNbUlMy4bPYW8lhttmca2XHdtMHuo112V8S6g681A-q8YNzHFPvLpUWOLumMAvVN44GhZ_"
"ZUL6_I4aXnj9FekZY4c6SmveySg0v6SDHOZhSTNsP5YqtGDlrMfUFxWBXnhFaDnLZe_MnL6xzvc5maME5aF4t6fOiNcX8zVDE-"
"tJrkuMV9PqR4zaQZ4lq4BedW8Wae76X7ZJIm5pKtDvm5TaO-"
"ZIsHQdST7LAnjvQKDS2zVml1yVnH84MpgPQWbydLO8R8tNUjZzYUicjY5ZlLSV9dn3ksf0MOW-"
"EzoCrma6rYXndQS9MXqIPXBDe9Xxmqzaz93oPf0Ff6ME35zaJ_qC_lo_neafH_l9x37Qib3LddIvttit5rgP20hHw-4UoJ-"
"TI5arMhdT2kz68VhX7YrsCZLHyhHY7SeQ7qZzXzLrHdJO_bnI2mAXPnAUP7_ook7re3IdfbPs-"
"3qfuA5gBl2zc2saQNubrNh3jNLIvrt7Yd2W_uBVMPiSVNbD_gY20eTMPoFhTj0_oGn17iSHLfA3LaDn_PAElCf4Lx8WTeTONY-"
"5octmnwhHFqWS-K174jB2AzHD-LhtBmVokcWYA-oxFis6I411sVcmh5Lh15mM7inphVjdZ1xt4T1p-"
"QhWdl1aAe9lzwUjbxN9deYJWc6NVakB8sKAYndD6CQgnxi7Vtz5NxmfRp64J8bVF_PqWOI-"
"wRJziv1SJfLfHUoiM2xvswhvgOzWqTfYs6eC9OEt_7WZBXLKDmM-pv67lnqolxwK2tqI_v4PnP1LfiZoubW1fkAHaI1g-GmqFjl_"
"xqYSPmu2AmPyqZd9h3VdcUsjDM-hSdtx9wl_8UYvdHphaP7UVjQ58Hi6BHbCzuk1n20g_nzPdpOpeBvtlvL6x-"
"ZD8o4tEaXnwHYw3IyVJ_HqJ9HlncA7Cu4eypM-ZPO97BaOJa3oI8DvL0mWNxJb7js25Blv2ej9Lxu6dKiTXuFjrSlzl-X6F9QT_Suo_"
"O6TXqWGz7xBvHFGNkBzCyQ2d8iOUkTfx2olMh7zvsOV-hzhIF0LslPR4PXLjDJwzr6UiSLvSHTp18gHj6wXNWV1nIWnqMUZ0G7Ivv6E_"
"LSqZdO01y0oGCw6eTEPNftSDmcp02cE4Whf8i5NM1T3HNwbb7je9NPdZpY06oY8AGz_"
"QF6R3Gd1u4PlDHdNgjdVAc1LPt0QN5iMcQO2M97vt1BmS_w8ETUV-Q43H3kX2e8_"
"eMovejmiLez5VF9q9maC0LsW0IZbslctgFPJ6h93vi3N6tkf0ui8yA3O9t9gBSPKhbJ1-_9VC7nvPy1v7A7BS_s-g2yNdd-"
"hjSfGStVUsPOwM1lrkgZ90pd_jjIwxP-54mJ3EFr_W7LXLcpQ-"
"LR4DYXs3UWyJkjjbY2UvF6tJfjQxbWeSXS87f5ZCCGBSAVoRwzmb9QJZnFt9fdKF-"
"64bMD7zoAtdbxViiVjB23bXFY0w5s6bs2uSkC7g3h2yM3JVDTG33WDexs9sH-wI_CCdRSGL5sSi2zw05gPW3ucmb_"
"8T1bPcuOscFir1g66gZff9PJXLwieJ9eDPjDWSvRo57n_8cunzHewBNXDf0rshRz5thbzf3lILYf3o2ObSZj_bxZUNcb_"
"YG5Ge9cA7R6ebrbMyAAEU72J4nWTfvjIEe8IjeM4QAxsHUbR_Z3INdIuc2Dcd88ax3B4fVtnjUlp_"
"ZZfKVHb2J8NZNBQQ74hxtV8ipzV5GU-"
"aAc2M9SiO2XZy0YvkqObDDMdYvi94aiXWtwZk9g8HTtt5TNnrKiGwDanPuTuij52NvV7SMO3r7IrJ1hDcXzGHrd2F7STtJip64Q1qf3e"
"G2_9hNcmw73hNz8TOTDXG9breW8gC_qLwiibHBbsNeItSk-Tbz3O1c_MaBJLEOFvgBXZYuLloDG5m-b3fIkR0VstRB-J6432FD7NsQ-"
"w7G39QM3XtgPygdIMOje1cz3hTb9qoHuPBkpHeQoXuffGt__qOX73uzz3-GzNX1P__FHXHsXk-Sk33QFeVL6HJNzmpO3qbOE_"
"5WoiCuQ-3byBfArS0KlSPDcBhyolQkGfnOvoO4fvHR_pGpyWJ_vCfHtfkzjQpX1Bcz-Fq_Qr7th_5D1AWuUMjqc0F_VMt-"
"u9Kvkv3KlI7xuNiq7bbqkH6D7Pe9yY530YbQL_sX5Lg_pXx5LY1gVMb7uv4lOe3TH_kbK0ufgynuafVb5KjvPTBgDekcYMacoQ-1S5_"
"PPP_7NvAbhuSLxFiLnEdnE_2WxA6uCHolfXTp4xvnCzjRB5YwR98SibGyf0UO-h7gPsqJ435Iv0cOIz0ZUjuZX3Cn3e-"
"Tj32AFD6mY3DDvjekkROk_c_I_r2W_nWkyxN1Qoy7xVy2D9yhT_"
"kzdtaGoQljrg8x16fuK92Rg6SM330ZlMjR4CF6ls9SsnL8Owjna9mtvuKgQQ4Hk128R8xZBjbJDexSim8Vv4BvDe5Abz-M6C6C-"
"5vcZbvfN7gnp4PXIdsdX0bmvq8r5Lslj7jm7ojB19_kgynLL9_tROUYhr_Zv59zXSMn15BLX6EEQjB4T_2C-"
"9vrBvm2HHXU5lPQzp9w0T2T9AU6NcnHgb09FXpnVcicCzDgmrMAcvZ2TOwZid93uh7AOOqGNEAwTI9j56ZOvrqhjsOjpFEPg9BN3_"
"tpRvy27CZ6m7f49SksJhe1dfTZ3m2DfNdwIPqdvOUNucMgNQfAlXkA370AWs7S8kZindsWOWx5c-8J41TGzly-XPuafNt0A-"
"a7i4IEVOiw4NmDxJjmqoYhJb6P-y53NXJwx2YM4-empu_ClMX6d1DP332fqucXP1Ok-E5RWdZG6zXvozpmwaeWL_"
"MRPNqTdCLEhHuLHN7vepcV93Jx2RtyfM9nQzp8xrmwhr4Z-cf__p_7_0VkiUI")
"eJyNW81y40hyrib13-qe6d3ZWR8cE4xwxHod4dkg8UfgyH9RJCg2AervViRryBqBgAYEpKVeYG8--AH2sgfHHnyzn6Dtky9-Ar-"
"AD34FJ0hRAIlkoSO6pzVUZVVWVuaXX2YV_xz-959-8x___rf_Swj5u3_60xf4h-QqdXJccSee79Pod-_gs__7z3w1B__m5bK2-"
"ezk9raw-rMl2yDfDV0esEmh4tNRoTHnPg3YAn6XmssolzafvV9NtPp7G8_VJO8rP01n1OWLgLq78jlDJgn5twli-"
"Rb5VHEDPg1p4XeFKvVH4YSm9TgoSZqe0O9ko8jWvtrkpOJOQ-"
"44FNlLNIeSOUcX7OqMYDuIXVVVbAsTZP05Q2XLyuazs1g2se4VOQLdPdA8JSspitiGA3Ja8acMzOju2G71e1VJrGORj5U58_"
"mYugWLzr30egclTc-2kw17DReBn95rTonP_Gwju7XXIegbyVKHI2ed00oJn1lJ79j5hhxW_HCEyOYloyzW-56cVV6YP6L8Z-oi_"
"m4owjOuVsh3VW8BRwzuesH8Fzb1nlZmT88l62XhmVer5CTyeDrxsNgDf1W0rHOo1slZlbpTh07YYpbWQdeLYh0a5LjKnCkP56lzkKW3-"
"c5vN0CygyXVJjmvhv4DmKDQpAsPs4Mkads2Xf-J52iBHUJnSn2-a0eyjjsjHnsB-"
"tKZT3kKawCr5M1np7exsWLZNsiGfuhOeFpHdeesCts-W70kh1WIbBfdnyG2sRnZ2J8DsqXPWFFKmWfcI5-qoDbjhTr1w8WCOnSO6KHF-"
"8fnuQI9PIc_IfikGqV4D29un5D9TH6oei7lPvvHgsXdoNCACKYBDxcQCBYd0fS5qUbi3AbkqOrTF-"
"6k411V3z77sIGL1NlZq3Onc7rA4kTKtKEN68_CAI35sio-"
"vxvwTy9YPFM8ziUtI87vVjEWHR2SF8Q5pXoPejOHvzDEvsXS27hahRzVQL_J9jnk4d93pbXOv49klKKcV_"
"VyvqwX87qk5iVZA98v5rWiAv4j5ctlPS_Bz4pcgvm1fLlo5I0ifK5LURxDLjLykm7kZUXOy5qaV0oajC3n1ZKRVxU9r5XkvKbA_"
"EU1rxfLIBuN0WEM_IV11JKSV8swVi_ldZDRyzAPrKPJ8HNsx_NEnts6x1qdfKp5kCgLv6-z-R8KA_b4h3_"
"AzkSRhXatNcl3NciYkIMKlZ_W6TCaCz1fWYxftRY5f9XpVR1MH0mszwV5bz3zAFKTQ91JOqcmcyIm3yYfa1_-LWCFyd-"
"3nzwIUwyn1O04K6TjrNaJ9uI9FNqLSI_dvLTyO02X4vFdclibcYcheVzVxHm8ZpKTGgUy4nkubvc3f0DxvNZbrb3LeVZr61oSUxKrJ-"
"WvYH3P8eajVN5Z61_ezX-IPw7IWc0DJCwMwIfSe4AYEu9hSA5qKyqDrJ_kUQgm165hbfrICtfMn2DnLetCTKwBrtVCn375F7qbt9-"
"94vfms3dGUu4OsGb5CHCGcB4148zuwU9f2HgWRVs4cvg4PYciFRO-nua7deAsLcin1F2muK5ixGvVL8lJ_Wc-8sKAo_"
"6lysK4rnfIcZ25c-o_pOMxzlnoPuvg23Vvzt3IKzBuV9bKJCNn1a_Ix80cr-gUjc9vzaMXjT3zJMZIXzFG2Tcm1uc-"
"qo2mDOH8eakk78RKmis2auS4MQ6B7voI_"
"xDjdQPOvLEIPLy2kpJ6r7Nvct0WOWxMl48BEmNSMRnjSZhIyA9gbZ8HPkP2HfOm0zj1J2Qtcmg9Uow35mRFXBs3bHLSCGbce0TxCfw3w"
"dkQ3tEEvtvk7m4-Ies41eNxl-SgyX9GY0QrG0KfaHbIt03qPESLiHKGWizGMiY5M_nY91y24Ahv1IyY1zSvyIcm9T0WT46cwRvOHe_"
"asAm8s-lTd5zGx5wsJ3JEYctpI_l3K3k76k947nLuAdPthfMR8zEddH2lQ_Tzob72ARQXWhVy2KIjD60jlG0O_qpMLFslH1_"
"7Nh3uTifePL0nZdunNsV3PEcdsNNnEVFEapGynIUBrRX2ev4UiUPDUIX-3GrCWcLaAP6tkFOsVwE4oMTjL8BWs9S419wmxotWm5y2-"
"AjoXUB9rDZXi3HcYufUBXmfsVX0oD5n7PW5lkmOWnTFKhAOVhTbtweyIXcZKivuA7X65KwF8MocL3xE-"
"IBqvK29F6Nbn8mnxi8hDTxAeafwqgrmq-Ic3YK4i-yHxt0W5uK8qmWD_UENNqcOtr5alLZiZZcbtYBXgfwcwbSDklbOrLlbN-TDevM_"
"VjlU3CFqA1U8x110lsvIgZGziPWHn7V1mMayFx1yegE1RaED_8HwRhXv_6JHTkB-AvQO7euqRUXo_xeQ82q-BwU-"
"km91cb18YZPDC8oj0oWsa4jXHZLji9CdUn-Z9huNCH2uXSenbXfymlaQvmLcz0L7km3AtrbPsPoL8EKMN-0uOWovfMrS_"
"Y28URbXfm2oY0BvVGejtI3nr1rHslfkvM4Z1J4t6o_38ARFE_pp-zM5aPv0F0zW0JTMWG0PVvJYDZcz9OxYb1tg9_E-"
"uyti3cHX2gF1lhi_MrLXvjTJ8SWdU6DYaZzQy5n918srcnTp-RO0r6Qlzh2pfy_75PCSPlKMG-qlpO44L-"
"00yGGHuUsUn1Vxrui0yFln6U-XLwu8J2ZowljpXKxq95E3wX1OV8UY0WmTkw73-YjitZmmi-"
"vmDpxbzZt7vpfuqUmamLN2euTXFo16mB0eBFH_sseeONJX1LXMmqjTJ-97nh_MAKh36gOytkPMezsD8t6CYhQZuz5zKRnrb2cey9-"
"Qo074DMiK-Zoqttcd1N10CTXzG5FO71eGqjZrv_fgN_SFPsxSfrPqNZbX8tF877T4_9cc-"
"80RClu6dSvkoEvROxCwn5aQLyRcKSFfJcddNqJA01P2N7S4lujWwP6rc--"
"G43Reg5pczbxj7LbJhy5n41nA3EXA0PsARRL34buQ2y2fF7rUfUAxX9n1g23c6EJu7vIRXofL4vvarhXZauEFMw-"
"JG00Ys13gZF0ezMLodhTj1OUtTr3GjOS-h-SsG_6RAWqE_"
"hTj5Mk8mcas7jU56tLgCePVcrkkXvuOHILNcKws6UKbmRVybALSjMeIzUri3G7WyJHpuXTsYTqLe2VmPVrXmXhPWM9DFp6V2YAa23PBS"
"9nU3157FRdyoodrQi4woSCc0sUYiiXEL95se56MwaRPmxfkW5P6ixl1HGHv2Eis2yHfrLHTpGM2wXs7epIvbtJQYt0uOTCpg_"
"f3JPF9oAk5xAR6Pqf-rp45Q02MAy5tRv19B891Rnknbna4uHlFDmGHaA2hqxk69snfrGzEfBfM5Edl8x77bmqbYhaGmZ-j8_"
"YD7vJfQuxeydDisYNobOjzYBX0iI0lsf7W2g8XzPdpOm-BvtlvMkw7sh8U8mgdL76bMYfkdK0_"
"D9HekSzuA5jXcPbUmfCnPe9jNHE9b0LOBnn6zLG4Et_9mbcgy_7Ix-"
"n4zalSYo27lY50uUDvz3NaMTH2PjqPl6g7sXv2r7xRjIU9wMIenfMRlns08duJXo186LHnQo0662hH75bK8Xjgtz0-ZVj_"
"RpLKwnPvNclHiJufPGdzlYWsVY6xqNeCffE9vW05WQPhXLzXJqc9KCJ8Og0xP1WLYn7W6wKPZFGYr0I7XcvE9QDWq1zPAbUI7PmZLpG-"
"YHyXdfbGwRIY1YNapMceqYPiWzl7_wOQhzgLsTMtxz293pAc9Dh4Hnr2cjzuPrLHc-GeUfQ-"
"VIs5EmrPK5McXM3RmhRiVhfK9ivkqA84O0fv88Q5u98gB30WmQG5z9uu5VP8pt8k3772R_"
"ues3xtY2B2it9V9Fvk2z59DGkhstamXYedgRrLXJD3_Rl3-OMjDE_7mhb3xffWzf0OOenTh9WjP2yvRurtEDJHF-"
"zspWJz7a96hq1M8ts1l-9zSC0MijgzQjQHqQHUYnzX0YcarB8yP_CiC1tvU6skagB9371cPMaQM-vCvkVO-4BzC8iyyN04xNRu_3QbK_"
"s22BfyfjiNQhLLeyWxfW7IIay_yzle_SeuSft30TmuUGuJraNm9PQ_V8jhZ4r32I2MN4-DBjkZfPlr6PI99_-"
"auB4YXJHjgTfH3mrmlKLYfwYWObKYj_"
"boZV18rzYYkl8NwgVEp1tosgkDYhPtYHeeZO27NwYGwA8GzxACGLdSd31kew9WhZxbNJzw1TPePdxU2-"
"FHO35mVck3VvQGwntrDCDYEedkq0bOLLYcz5gDzo31GvXYdnGSiuXr5NAKJ1jPK3pbJNa1AWf2DAZP2zqnbPWGEdkW1NzcndJHz8feqm"
"gZ9_nWRWTrCG8umMPe3oHlknaSlHLifujt7I52_cdqkxPL8Z6Yi5-ZrIvrcKuzlgf4ReUVSYwNVhf2EqEmLXSZ5-"
"7m4lfOI4l1MMEP6LokcbH6shxjrtUjx1ZUiFIH4XHifoUFMW5BjDsYL1MzdByAnYD6QyZH96hmvBW2rE2_buWxSO2fobtNvre-_"
"MUr2N78y18hQ_X9L__qjjl2NyfJyZ7lpn2R0OWavG84BYs6T_j7iaK4jrRuozMH9zUpVH4Mw1vIfVKJZOQ16w7id-mj_R9Dk8V-"
"d09OGotnGhWeqM9l8DK7Rr63Q_8h6tjWKGTvhaCXqWW_Z7Hr5KA2oxPc_3dqs536wm6RA9ub7nnvrAv90r4gJ_aM8vXVMoJFGe_"
"m7EtyZtOf-Sv7Sp-DIe5J2R1ybHsPDNhBGuuNmBvYUJPYfO75P3aBxzAkLyTGmuQ8Opvo2w97OCHolfTRdC_"
"HBpywgQ0s0PdFYky0r8ih7QG-o9w37mfYA3IU6cmQGsn4intp2yafbIAUPqETcEPbG9HICdL-p2d_X8W-"
"jnR5ok6IcbQYP23gCDblz9hZ67omjDkbYs6m7gvdk2ukjO-0DKHeHz5Ez-1ZSlaOv1tw_ia70xcctsjRcLqP34i5ydAi-"
"aFVSfGq0lfwquEd6O2HEa1FcH-bo-z264b35Gz4MmL740vP3Pd1jfyw5gvX3B0z-Pd3BajuC-"
"u3N1HZheFv9vdurhvk9Bpy6QuUOggG59SvuG-9bpHvq1FHbDED7fwpF90JSV-"
"hU5t8Glq7U6H3S8XMuQADrjkLIGfvxkROT3yP6XoI46gb0gDBsAT3uGmSb26o4_AoaTTDIHTTd3SaHt8R3UTv9VZfi8JiclVDR5_"
"lblvkh5YD0e8UTG_EHQapOQBOzAP4aQloOU_L64l1bjvkqOMtvCfsXkDfm8vXa1-T79tuwHx3VXiACj0WPHuQGNOcVNelxM9xf-"
"WuQQ7v2JxhPNzQyvswZbX-HdTtdz-m6vbV7xQpvv9T1jXQ25r3Ub2y4lPrF_"
"cIHuWkMhFiwr1Jju73va2Ke7G47A05uefzER0945xXQ994_M8_z__r_wF2XX6H")
.ok());
TlBufferParser parser(&en);
auto result = telegram_api::help_getCountriesList::fetch_result(parser);

View File

@ -204,7 +204,7 @@ static td_api::object_ptr<td_api::ChatEventAction> get_chat_event_action_object(
if (message == nullptr) {
return nullptr;
}
return td_api::make_object<td_api::chatEventMessageDeleted>(std::move(message));
return td_api::make_object<td_api::chatEventMessageDeleted>(std::move(message), false);
}
case telegram_api::channelAdminLogEventActionChangeStickerSet::ID: {
auto action = move_tl_object_as<telegram_api::channelAdminLogEventActionChangeStickerSet>(action_ptr);
@ -380,6 +380,12 @@ static td_api::object_ptr<td_api::ChatEventAction> get_chat_event_action_object(
LOG(ERROR) << "Receive " << to_string(action);
return nullptr;
}
bool edit_is_closed = old_topic_info.is_closed() != new_topic_info.is_closed();
bool edit_is_hidden = old_topic_info.is_hidden() != new_topic_info.is_hidden();
if (edit_is_hidden && !(!new_topic_info.is_hidden() && edit_is_closed && !new_topic_info.is_closed())) {
return td_api::make_object<td_api::chatEventForumTopicToggleIsHidden>(
new_topic_info.get_forum_topic_info_object(td));
}
if (old_topic_info.is_closed() != new_topic_info.is_closed()) {
return td_api::make_object<td_api::chatEventForumTopicToggleIsClosed>(
new_topic_info.get_forum_topic_info_object(td));
@ -411,6 +417,10 @@ static td_api::object_ptr<td_api::ChatEventAction> get_chat_event_action_object(
return td_api::make_object<td_api::chatEventForumTopicPinned>(old_topic_info.get_forum_topic_info_object(td),
new_topic_info.get_forum_topic_info_object(td));
}
case telegram_api::channelAdminLogEventActionToggleAntiSpam::ID: {
auto action = move_tl_object_as<telegram_api::channelAdminLogEventActionToggleAntiSpam>(action_ptr);
return td_api::make_object<td_api::chatEventIsAggressiveAntiSpamEnabledToggled>(action->new_value_);
}
default:
UNREACHABLE();
return nullptr;
@ -457,6 +467,7 @@ class GetChannelAdminLogQuery final : public Td::ResultHandler {
td_->contacts_manager_->on_get_users(std::move(events->users_), "on_get_event_log");
td_->contacts_manager_->on_get_chats(std::move(events->chats_), "on_get_event_log");
auto anti_spam_user_id = UserId(G()->get_option_integer("anti_spam_bot_user_id"));
auto result = td_api::make_object<td_api::chatEvents>();
result->events_.reserve(events->events_.size());
for (auto &event : events->events_) {
@ -477,6 +488,10 @@ class GetChannelAdminLogQuery final : public Td::ResultHandler {
if (action == nullptr) {
continue;
}
if (user_id == anti_spam_user_id && anti_spam_user_id.is_valid() &&
action->get_id() == td_api::chatEventMessageDeleted::ID) {
static_cast<td_api::chatEventMessageDeleted *>(action.get())->can_report_anti_spam_false_positive_ = true;
}
if (user_id == ContactsManager::get_channel_bot_user_id() && actor_dialog_id.is_valid() &&
actor_dialog_id.get_type() != DialogType::User) {
user_id = UserId();

View File

@ -151,4 +151,29 @@ int64 DialogId::get_peer_id(const tl_object_ptr<telegram_api::Peer> &peer) {
}
}
DialogId DialogId::get_message_dialog_id(const telegram_api::Message *message_ptr) {
CHECK(message_ptr != nullptr);
switch (message_ptr->get_id()) {
case telegram_api::messageEmpty::ID: {
auto message = static_cast<const telegram_api::messageEmpty *>(message_ptr);
return message->peer_id_ == nullptr ? DialogId() : DialogId(message->peer_id_);
}
case telegram_api::message::ID: {
auto message = static_cast<const telegram_api::message *>(message_ptr);
return DialogId(message->peer_id_);
}
case telegram_api::messageService::ID: {
auto message = static_cast<const telegram_api::messageService *>(message_ptr);
return DialogId(message->peer_id_);
}
default:
UNREACHABLE();
return DialogId();
}
}
DialogId DialogId::get_message_dialog_id(const tl_object_ptr<telegram_api::Message> &message_ptr) {
return get_message_dialog_id(message_ptr.get());
}
} // namespace td

View File

@ -66,6 +66,10 @@ class DialogId {
ChannelId get_channel_id() const;
SecretChatId get_secret_chat_id() const;
static DialogId get_message_dialog_id(const telegram_api::Message *message_ptr);
static DialogId get_message_dialog_id(const tl_object_ptr<telegram_api::Message> &message_ptr);
template <class StorerT>
void store(StorerT &storer) const {
storer.store_long(id);

View File

@ -51,36 +51,57 @@ static int32 get_mute_until(int32 mute_for) {
}
Result<DialogNotificationSettings> get_dialog_notification_settings(
td_api::object_ptr<td_api::chatNotificationSettings> &&notification_settings, bool old_silent_send_message) {
td_api::object_ptr<td_api::chatNotificationSettings> &&notification_settings,
const DialogNotificationSettings *old_settings) {
if (notification_settings == nullptr) {
return Status::Error(400, "New notification settings must be non-empty");
}
CHECK(old_settings != nullptr);
int32 mute_until =
notification_settings->use_default_mute_for_ ? 0 : get_mute_until(notification_settings->mute_for_);
return DialogNotificationSettings(
notification_settings->use_default_mute_for_, mute_until,
get_notification_sound(notification_settings->use_default_sound_, notification_settings->sound_id_),
notification_settings->use_default_show_preview_, notification_settings->show_preview_, old_silent_send_message,
notification_settings->use_default_disable_pinned_message_notifications_,
notification_settings->disable_pinned_message_notifications_,
notification_settings->use_default_disable_mention_notifications_,
notification_settings->disable_mention_notifications_);
auto notification_sound =
get_notification_sound(notification_settings->use_default_sound_, notification_settings->sound_id_);
if (is_notification_sound_default(old_settings->sound) && is_notification_sound_default(notification_sound)) {
notification_sound = dup_notification_sound(old_settings->sound);
}
return DialogNotificationSettings(notification_settings->use_default_mute_for_, mute_until,
std::move(notification_sound), notification_settings->use_default_show_preview_,
notification_settings->show_preview_, old_settings->silent_send_message,
notification_settings->use_default_disable_pinned_message_notifications_,
notification_settings->disable_pinned_message_notifications_,
notification_settings->use_default_disable_mention_notifications_,
notification_settings->disable_mention_notifications_);
}
DialogNotificationSettings get_dialog_notification_settings(tl_object_ptr<telegram_api::peerNotifySettings> &&settings,
bool old_use_default_disable_pinned_message_notifications,
bool old_disable_pinned_message_notifications,
bool old_use_default_disable_mention_notifications,
bool old_disable_mention_notifications) {
if (settings == nullptr) {
return DialogNotificationSettings();
const DialogNotificationSettings *old_settings) {
bool old_use_default_disable_pinned_message_notifications = true;
bool old_disable_pinned_message_notifications = false;
bool old_use_default_disable_mention_notifications = true;
bool old_disable_mention_notifications = false;
if (old_settings != nullptr) {
old_use_default_disable_pinned_message_notifications =
old_settings->use_default_disable_pinned_message_notifications;
old_disable_pinned_message_notifications = old_settings->disable_pinned_message_notifications;
old_use_default_disable_mention_notifications = old_settings->use_default_disable_mention_notifications;
old_disable_mention_notifications = old_settings->disable_mention_notifications;
}
if (settings == nullptr) {
auto result = DialogNotificationSettings();
result.use_default_disable_pinned_message_notifications = old_use_default_disable_pinned_message_notifications;
result.disable_pinned_message_notifications = old_disable_pinned_message_notifications;
result.use_default_disable_mention_notifications = old_use_default_disable_mention_notifications;
result.disable_mention_notifications = old_disable_mention_notifications;
return result;
}
bool use_default_mute_until = (settings->flags_ & telegram_api::peerNotifySettings::MUTE_UNTIL_MASK) == 0;
bool use_default_show_preview = (settings->flags_ & telegram_api::peerNotifySettings::SHOW_PREVIEWS_MASK) == 0;
auto mute_until = use_default_mute_until || settings->mute_until_ <= G()->unix_time() ? 0 : settings->mute_until_;
bool silent_send_message =
(settings->flags_ & telegram_api::peerNotifySettings::SILENT_MASK) == 0 ? false : settings->silent_;
bool silent_send_message = settings->silent_;
return {use_default_mute_until,
mute_until,
get_notification_sound(settings.get()),
@ -99,4 +120,26 @@ bool are_default_dialog_notification_settings(const DialogNotificationSettings &
settings.use_default_disable_mention_notifications;
}
NeedUpdateDialogNotificationSettings need_update_dialog_notification_settings(
const DialogNotificationSettings *current_settings, const DialogNotificationSettings &new_settings) {
NeedUpdateDialogNotificationSettings result;
result.need_update_server = current_settings->mute_until != new_settings.mute_until ||
!are_equivalent_notification_sounds(current_settings->sound, new_settings.sound) ||
current_settings->show_preview != new_settings.show_preview ||
current_settings->use_default_mute_until != new_settings.use_default_mute_until ||
current_settings->use_default_show_preview != new_settings.use_default_show_preview;
result.need_update_local =
current_settings->use_default_disable_pinned_message_notifications !=
new_settings.use_default_disable_pinned_message_notifications ||
current_settings->disable_pinned_message_notifications != new_settings.disable_pinned_message_notifications ||
current_settings->use_default_disable_mention_notifications !=
new_settings.use_default_disable_mention_notifications ||
current_settings->disable_mention_notifications != new_settings.disable_mention_notifications;
result.are_changed = result.need_update_server || result.need_update_local ||
current_settings->is_synchronized != new_settings.is_synchronized ||
current_settings->is_use_default_fixed != new_settings.is_use_default_fixed ||
are_different_equivalent_notification_sounds(current_settings->sound, new_settings.sound);
return result;
}
} // namespace td

View File

@ -61,14 +61,20 @@ td_api::object_ptr<td_api::chatNotificationSettings> get_chat_notification_setti
const DialogNotificationSettings *notification_settings);
Result<DialogNotificationSettings> get_dialog_notification_settings(
td_api::object_ptr<td_api::chatNotificationSettings> &&notification_settings, bool old_silent_send_message);
td_api::object_ptr<td_api::chatNotificationSettings> &&notification_settings,
const DialogNotificationSettings *old_settings);
DialogNotificationSettings get_dialog_notification_settings(tl_object_ptr<telegram_api::peerNotifySettings> &&settings,
bool old_use_default_disable_pinned_message_notifications,
bool old_disable_pinned_message_notifications,
bool old_use_default_disable_mention_notifications,
bool old_disable_mention_notifications);
const DialogNotificationSettings *old_settings);
bool are_default_dialog_notification_settings(const DialogNotificationSettings &settings, bool compare_sound);
struct NeedUpdateDialogNotificationSettings {
bool need_update_server = false;
bool need_update_local = false;
bool are_changed = false;
};
NeedUpdateDialogNotificationSettings need_update_dialog_notification_settings(
const DialogNotificationSettings *current_settings, const DialogNotificationSettings &new_settings);
} // namespace td

View File

@ -7,6 +7,7 @@
#include "td/telegram/ForumTopic.h"
#include "td/telegram/DraftMessage.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/ServerMessageId.h"
#include "td/telegram/Td.h"
@ -14,39 +15,47 @@
namespace td {
ForumTopic::ForumTopic(Td *td, tl_object_ptr<telegram_api::ForumTopic> &&forum_topic_ptr) {
ForumTopic::ForumTopic(Td *td, tl_object_ptr<telegram_api::ForumTopic> &&forum_topic_ptr,
const DialogNotificationSettings *current_notification_settings) {
CHECK(forum_topic_ptr != nullptr);
if (forum_topic_ptr->get_id() != telegram_api::forumTopic::ID) {
LOG(INFO) << "Receive " << to_string(forum_topic_ptr);
return;
}
info_ = ForumTopicInfo(forum_topic_ptr);
auto *forum_topic = static_cast<telegram_api::forumTopic *>(forum_topic_ptr.get());
is_short_ = forum_topic->short_;
is_pinned_ = forum_topic->pinned_;
notification_settings_ =
get_dialog_notification_settings(std::move(forum_topic->notify_settings_), current_notification_settings);
draft_message_ = get_draft_message(td->contacts_manager_.get(), std::move(forum_topic->draft_));
if (is_short_) {
return;
}
last_message_id_ = MessageId(ServerMessageId(forum_topic->top_message_));
is_pinned_ = forum_topic->pinned_;
unread_count_ = forum_topic->unread_count_;
last_read_inbox_message_id_ = MessageId(ServerMessageId(forum_topic->read_inbox_max_id_));
last_read_outbox_message_id_ = MessageId(ServerMessageId(forum_topic->read_outbox_max_id_));
unread_mention_count_ = forum_topic->unread_mentions_count_;
unread_reaction_count_ = forum_topic->unread_reactions_count_;
notification_settings_ =
get_dialog_notification_settings(std::move(forum_topic->notify_settings_), false, false, false, false);
draft_message_ = get_draft_message(td->contacts_manager_.get(), std::move(forum_topic->draft_));
}
td_api::object_ptr<td_api::forumTopic> ForumTopic::get_forum_topic_object(Td *td) const {
if (is_empty()) {
td_api::object_ptr<td_api::forumTopic> ForumTopic::get_forum_topic_object(Td *td, DialogId dialog_id,
const ForumTopicInfo &info) const {
if (info.is_empty()) {
return nullptr;
}
// TODO draft_message = can_send_message(dialog_id, info_.get_top_thread_message_id()).is_ok() ? ... : nullptr;
// TODO last_message
auto last_message =
td->messages_manager_->get_message_object({dialog_id, last_message_id_}, "get_forum_topic_object");
auto draft_message = get_draft_message_object(draft_message_);
return td_api::make_object<td_api::forumTopic>(
info_.get_forum_topic_info_object(td), nullptr, is_pinned_, unread_count_, last_read_inbox_message_id_.get(),
last_read_outbox_message_id_.get(), unread_mention_count_, unread_reaction_count_,
get_chat_notification_settings_object(&notification_settings_), std::move(draft_message));
info.get_forum_topic_info_object(td), std::move(last_message), is_pinned_, unread_count_,
last_read_inbox_message_id_.get(), last_read_outbox_message_id_.get(), unread_mention_count_,
unread_reaction_count_, get_chat_notification_settings_object(&notification_settings_), std::move(draft_message));
}
} // namespace td

View File

@ -6,7 +6,9 @@
//
#pragma once
#include "td/telegram/DialogId.h"
#include "td/telegram/DialogNotificationSettings.h"
#include "td/telegram/DraftMessage.h"
#include "td/telegram/ForumTopicInfo.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/td_api.h"
@ -16,14 +18,13 @@
namespace td {
class DraftMessage;
class Td;
class ForumTopic {
ForumTopicInfo info_;
MessageId last_message_id_;
bool is_short_ = false;
bool is_pinned_ = false;
int32 unread_count_ = 0;
MessageId last_message_id_;
MessageId last_read_inbox_message_id_;
MessageId last_read_outbox_message_id_;
int32 unread_mention_count_ = 0;
@ -34,17 +35,29 @@ class ForumTopic {
public:
ForumTopic() = default;
ForumTopic(Td *td, tl_object_ptr<telegram_api::ForumTopic> &&forum_topic_ptr);
ForumTopic(Td *td, tl_object_ptr<telegram_api::ForumTopic> &&forum_topic_ptr,
const DialogNotificationSettings *current_notification_settings);
bool is_empty() const {
return info_.is_empty();
bool is_short() const {
return is_short_;
}
MessageId get_top_thread_message_id() const {
return info_.get_top_thread_message_id();
DialogNotificationSettings *get_notification_settings() {
return &notification_settings_;
}
td_api::object_ptr<td_api::forumTopic> get_forum_topic_object(Td *td) const;
const DialogNotificationSettings *get_notification_settings() const {
return &notification_settings_;
}
td_api::object_ptr<td_api::forumTopic> get_forum_topic_object(Td *td, DialogId dialog_id,
const ForumTopicInfo &info) const;
template <class StorerT>
void store(StorerT &storer) const;
template <class ParserT>
void parse(ParserT &parser);
};
} // namespace td

106
td/telegram/ForumTopic.hpp Normal file
View File

@ -0,0 +1,106 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
//
// 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/DialogNotificationSettings.hpp"
#include "td/telegram/DraftMessage.hpp"
#include "td/telegram/ForumTopic.h"
#include "td/utils/common.h"
#include "td/utils/tl_helpers.h"
namespace td {
template <class StorerT>
void ForumTopic::store(StorerT &storer) const {
bool has_unread_count = unread_count_ != 0;
bool has_last_message_id = last_message_id_.is_valid();
bool has_last_read_inbox_message_id = last_read_inbox_message_id_.is_valid();
bool has_last_read_outbox_message_id = last_read_outbox_message_id_.is_valid();
bool has_unread_mention_count = unread_mention_count_ != 0;
bool has_unread_reaction_count = unread_reaction_count_ != 0;
bool has_draft_message = draft_message_ != nullptr;
BEGIN_STORE_FLAGS();
STORE_FLAG(is_short_);
STORE_FLAG(is_pinned_);
STORE_FLAG(has_unread_count);
STORE_FLAG(has_last_message_id);
STORE_FLAG(has_last_read_inbox_message_id);
STORE_FLAG(has_last_read_outbox_message_id);
STORE_FLAG(has_unread_mention_count);
STORE_FLAG(has_unread_reaction_count);
STORE_FLAG(has_draft_message);
END_STORE_FLAGS();
if (has_unread_count) {
td::store(unread_count_, storer);
}
if (has_last_message_id) {
td::store(last_message_id_, storer);
}
if (has_last_read_inbox_message_id) {
td::store(last_read_inbox_message_id_, storer);
}
if (has_last_read_outbox_message_id) {
td::store(last_read_outbox_message_id_, storer);
}
if (has_unread_mention_count) {
td::store(unread_mention_count_, storer);
}
if (has_unread_reaction_count) {
td::store(unread_reaction_count_, storer);
}
td::store(notification_settings_, storer);
if (has_draft_message) {
td::store(draft_message_, storer);
}
}
template <class ParserT>
void ForumTopic::parse(ParserT &parser) {
bool has_unread_count;
bool has_last_message_id;
bool has_last_read_inbox_message_id;
bool has_last_read_outbox_message_id;
bool has_unread_mention_count;
bool has_unread_reaction_count;
bool has_draft_message;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(is_short_);
PARSE_FLAG(is_pinned_);
PARSE_FLAG(has_unread_count);
PARSE_FLAG(has_last_message_id);
PARSE_FLAG(has_last_read_inbox_message_id);
PARSE_FLAG(has_last_read_outbox_message_id);
PARSE_FLAG(has_unread_mention_count);
PARSE_FLAG(has_unread_reaction_count);
PARSE_FLAG(has_draft_message);
END_PARSE_FLAGS();
if (has_unread_count) {
td::parse(unread_count_, parser);
}
if (has_last_message_id) {
td::parse(last_message_id_, parser);
}
if (has_last_read_inbox_message_id) {
td::parse(last_read_inbox_message_id_, parser);
}
if (has_last_read_outbox_message_id) {
td::parse(last_read_outbox_message_id_, parser);
}
if (has_unread_mention_count) {
td::parse(unread_mention_count_, parser);
}
if (has_unread_reaction_count) {
td::parse(unread_reaction_count_, parser);
}
td::parse(notification_settings_, parser);
if (has_draft_message) {
td::parse(draft_message_, parser);
}
}
} // namespace td

View File

@ -9,6 +9,9 @@
namespace td {
td_api::object_ptr<td_api::MessageContent> ForumTopicEditedData::get_message_content_object() const {
if (edit_is_hidden_ && !(!is_hidden_ && edit_is_closed_ && !is_closed_)) {
return td_api::make_object<td_api::messageForumTopicIsHiddenToggled>(is_hidden_);
}
if (edit_is_closed_) {
return td_api::make_object<td_api::messageForumTopicIsClosedToggled>(is_closed_);
}
@ -19,7 +22,8 @@ td_api::object_ptr<td_api::MessageContent> ForumTopicEditedData::get_message_con
bool operator==(const ForumTopicEditedData &lhs, const ForumTopicEditedData &rhs) {
return lhs.title_ == rhs.title_ && lhs.icon_custom_emoji_id_ == rhs.icon_custom_emoji_id_ &&
lhs.edit_icon_custom_emoji_id_ == rhs.edit_icon_custom_emoji_id_ &&
lhs.edit_is_closed_ == rhs.edit_is_closed_ && lhs.is_closed_ == rhs.is_closed_;
lhs.edit_is_closed_ == rhs.edit_is_closed_ && lhs.is_closed_ == rhs.is_closed_ &&
lhs.edit_is_hidden_ == rhs.edit_is_hidden_ && lhs.is_hidden_ == rhs.is_hidden_;
}
bool operator!=(const ForumTopicEditedData &lhs, const ForumTopicEditedData &rhs) {
@ -36,6 +40,9 @@ StringBuilder &operator<<(StringBuilder &string_builder, const ForumTopicEditedD
if (topic_edited_data.edit_is_closed_) {
string_builder << "set is_closed to " << topic_edited_data.is_closed_;
}
if (topic_edited_data.edit_is_hidden_) {
string_builder << "set is_hidden to " << topic_edited_data.is_hidden_;
}
return string_builder;
}

View File

@ -20,6 +20,8 @@ class ForumTopicEditedData {
bool edit_icon_custom_emoji_id_ = false;
bool edit_is_closed_ = false;
bool is_closed_ = false;
bool edit_is_hidden_ = false;
bool is_hidden_ = false;
friend bool operator==(const ForumTopicEditedData &lhs, const ForumTopicEditedData &rhs);
@ -31,16 +33,18 @@ class ForumTopicEditedData {
ForumTopicEditedData() = default;
ForumTopicEditedData(string &&title, bool edit_icon_custom_emoji_id, int64 icon_custom_emoji_id, bool edit_is_closed,
bool is_closed)
bool is_closed, bool edit_is_hidden, bool is_hidden)
: title_(std::move(title))
, icon_custom_emoji_id_(icon_custom_emoji_id)
, edit_icon_custom_emoji_id_(edit_icon_custom_emoji_id)
, edit_is_closed_(edit_is_closed)
, is_closed_(is_closed) {
, is_closed_(is_closed)
, edit_is_hidden_(edit_is_hidden)
, is_hidden_(is_hidden) {
}
bool is_empty() const {
return title_.empty() && !edit_icon_custom_emoji_id_ && !edit_is_closed_;
return title_.empty() && !edit_icon_custom_emoji_id_ && !edit_is_closed_ && !edit_is_hidden_;
}
const string &get_title() const {

View File

@ -23,6 +23,7 @@ void ForumTopicEditedData::store(StorerT &storer) const {
STORE_FLAG(is_closed_);
STORE_FLAG(has_title);
STORE_FLAG(has_icon_custom_emoji_id);
STORE_FLAG(is_hidden_);
END_STORE_FLAGS();
if (has_title) {
td::store(title_, storer);
@ -42,6 +43,7 @@ void ForumTopicEditedData::parse(ParserT &parser) {
PARSE_FLAG(is_closed_);
PARSE_FLAG(has_title);
PARSE_FLAG(has_icon_custom_emoji_id);
PARSE_FLAG(is_hidden_);
END_PARSE_FLAGS();
if (has_title) {
td::parse(title_, parser);

View File

@ -28,6 +28,7 @@ ForumTopicInfo::ForumTopicInfo(const tl_object_ptr<telegram_api::ForumTopic> &fo
creator_dialog_id_ = DialogId(forum_topic->from_id_);
is_outgoing_ = forum_topic->my_;
is_closed_ = forum_topic->closed_;
is_hidden_ = forum_topic->hidden_;
if (creation_date_ <= 0 || !top_thread_message_id_.is_valid() || !creator_dialog_id_.is_valid()) {
LOG(ERROR) << "Receive " << to_string(forum_topic_ptr);
@ -48,6 +49,10 @@ bool ForumTopicInfo::apply_edited_data(const ForumTopicEditedData &edited_data)
is_closed_ = edited_data.is_closed_;
is_changed = true;
}
if (edited_data.edit_is_hidden_ && edited_data.is_hidden_ != is_hidden_) {
is_hidden_ = edited_data.is_hidden_;
is_changed = true;
}
return is_changed;
}
@ -57,9 +62,20 @@ td_api::object_ptr<td_api::forumTopicInfo> ForumTopicInfo::get_forum_topic_info_
}
auto creator_id = get_message_sender_object_const(td, creator_dialog_id_, "get_forum_topic_info_object");
return td_api::make_object<td_api::forumTopicInfo>(top_thread_message_id_.get(), title_,
icon_.get_forum_topic_icon_object(), creation_date_,
std::move(creator_id), is_outgoing_, is_closed_);
return td_api::make_object<td_api::forumTopicInfo>(
top_thread_message_id_.get(), title_, icon_.get_forum_topic_icon_object(), creation_date_, std::move(creator_id),
top_thread_message_id_ == MessageId(ServerMessageId(1)), is_outgoing_, is_closed_, is_hidden_);
}
bool operator==(const ForumTopicInfo &lhs, const ForumTopicInfo &rhs) {
return lhs.top_thread_message_id_ == rhs.top_thread_message_id_ && lhs.title_ == rhs.title_ &&
lhs.icon_ == rhs.icon_ && lhs.creation_date_ == rhs.creation_date_ &&
lhs.creator_dialog_id_ == rhs.creator_dialog_id_ && lhs.is_outgoing_ == rhs.is_outgoing_ &&
lhs.is_closed_ == rhs.is_closed_ && lhs.is_hidden_ == rhs.is_hidden_;
}
bool operator!=(const ForumTopicInfo &lhs, const ForumTopicInfo &rhs) {
return !(lhs == rhs);
}
StringBuilder &operator<<(StringBuilder &string_builder, const ForumTopicInfo &topic_info) {

View File

@ -28,6 +28,10 @@ class ForumTopicInfo {
DialogId creator_dialog_id_;
bool is_outgoing_ = false;
bool is_closed_ = false;
bool is_hidden_ = false;
friend bool operator==(const ForumTopicInfo &lhs, const ForumTopicInfo &rhs);
friend bool operator!=(const ForumTopicInfo &lhs, const ForumTopicInfo &rhs);
friend StringBuilder &operator<<(StringBuilder &string_builder, const ForumTopicInfo &topic_info);
@ -37,14 +41,15 @@ class ForumTopicInfo {
explicit ForumTopicInfo(const tl_object_ptr<telegram_api::ForumTopic> &forum_topic_ptr);
ForumTopicInfo(MessageId top_thread_message_id, string title, ForumTopicIcon icon, int32 creation_date,
DialogId creator_dialog_id, bool is_outgoing, bool is_closed)
DialogId creator_dialog_id, bool is_outgoing, bool is_closed, bool is_hidden)
: top_thread_message_id_(top_thread_message_id)
, title_(std::move(title))
, icon_(std::move(icon))
, creation_date_(creation_date)
, creator_dialog_id_(creator_dialog_id)
, is_outgoing_(is_outgoing)
, is_closed_(is_closed) {
, is_closed_(is_closed)
, is_hidden_(is_hidden) {
}
bool is_empty() const {
@ -67,11 +72,24 @@ class ForumTopicInfo {
return is_closed_;
}
bool is_hidden() const {
return is_hidden_;
}
bool apply_edited_data(const ForumTopicEditedData &edited_data);
td_api::object_ptr<td_api::forumTopicInfo> get_forum_topic_info_object(Td *td) const;
template <class StorerT>
void store(StorerT &storer) const;
template <class ParserT>
void parse(ParserT &parser);
};
bool operator==(const ForumTopicInfo &lhs, const ForumTopicInfo &rhs);
bool operator!=(const ForumTopicInfo &lhs, const ForumTopicInfo &rhs);
StringBuilder &operator<<(StringBuilder &string_builder, const ForumTopicInfo &topic_info);
} // namespace td

View File

@ -0,0 +1,46 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
//
// 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/ForumTopicInfo.h"
#include "td/telegram/ForumTopicIcon.hpp"
#include "td/utils/common.h"
#include "td/utils/tl_helpers.h"
namespace td {
template <class StorerT>
void ForumTopicInfo::store(StorerT &storer) const {
BEGIN_STORE_FLAGS();
STORE_FLAG(is_outgoing_);
STORE_FLAG(is_closed_);
STORE_FLAG(is_hidden_);
END_STORE_FLAGS();
td::store(top_thread_message_id_, storer);
td::store(title_, storer);
td::store(icon_, storer);
td::store(creation_date_, storer);
td::store(creator_dialog_id_, storer);
}
template <class ParserT>
void ForumTopicInfo::parse(ParserT &parser) {
BEGIN_PARSE_FLAGS();
PARSE_FLAG(is_outgoing_);
PARSE_FLAG(is_closed_);
PARSE_FLAG(is_hidden_);
END_PARSE_FLAGS();
td::parse(top_thread_message_id_, parser);
td::parse(title_, parser);
td::parse(icon_, parser);
td::parse(creation_date_, parser);
td::parse(creator_dialog_id_, parser);
}
} // namespace td

View File

@ -11,18 +11,29 @@
#include "td/telegram/ChannelId.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/CustomEmojiId.h"
#include "td/telegram/ForumTopic.h"
#include "td/telegram/ForumTopic.hpp"
#include "td/telegram/ForumTopicIcon.h"
#include "td/telegram/ForumTopicInfo.hpp"
#include "td/telegram/Global.h"
#include "td/telegram/logevent/LogEvent.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/MessageThreadDb.h"
#include "td/telegram/misc.h"
#include "td/telegram/NotificationManager.h"
#include "td/telegram/NotificationSettingsManager.h"
#include "td/telegram/OptionManager.h"
#include "td/telegram/ServerMessageId.h"
#include "td/telegram/Td.h"
#include "td/telegram/TdDb.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/UpdatesManager.h"
#include "td/utils/buffer.h"
#include "td/utils/logging.h"
#include "td/utils/Random.h"
#include "td/utils/Slice.h"
#include "td/utils/tl_helpers.h"
namespace td {
@ -93,7 +104,7 @@ class CreateForumTopicQuery final : public Td::ResultHandler {
auto forum_topic_info =
td::make_unique<ForumTopicInfo>(MessageId(ServerMessageId(service_message->id_)), action->title_,
ForumTopicIcon(action->icon_color_, action->icon_emoji_id_),
service_message->date_, creator_dialog_id_, true, false);
service_message->date_, creator_dialog_id_, true, false, false);
td_->updates_manager_->on_get_updates(
std::move(ptr),
PromiseCreator::lambda([dialog_id = DialogId(channel_id_), forum_topic_info = std::move(forum_topic_info),
@ -118,20 +129,25 @@ class EditForumTopicQuery final : public Td::ResultHandler {
explicit EditForumTopicQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(ChannelId channel_id, MessageId top_thread_message_id, const string &title,
CustomEmojiId icon_custom_emoji_id) {
void send(ChannelId channel_id, MessageId top_thread_message_id, bool edit_title, const string &title,
bool edit_custom_emoji_id, CustomEmojiId icon_custom_emoji_id) {
channel_id_ = channel_id;
top_thread_message_id_ = top_thread_message_id;
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
CHECK(input_channel != nullptr);
int32 flags =
telegram_api::channels_editForumTopic::TITLE_MASK | telegram_api::channels_editForumTopic::ICON_EMOJI_ID_MASK;
int32 flags = 0;
if (edit_title) {
flags |= telegram_api::channels_editForumTopic::TITLE_MASK;
}
if (edit_custom_emoji_id) {
flags |= telegram_api::channels_editForumTopic::ICON_EMOJI_ID_MASK;
}
send_query(G()->net_query_creator().create(
telegram_api::channels_editForumTopic(flags, std::move(input_channel),
top_thread_message_id.get_server_message_id().get(), title,
icon_custom_emoji_id.get(), false),
top_thread_message_id_.get_server_message_id().get(), title,
icon_custom_emoji_id.get(), false, false),
{{channel_id}}));
}
@ -145,8 +161,23 @@ class EditForumTopicQuery final : public Td::ResultHandler {
int32 flags = telegram_api::channels_editForumTopic::CLOSED_MASK;
send_query(G()->net_query_creator().create(
telegram_api::channels_editForumTopic(flags, std::move(input_channel),
top_thread_message_id.get_server_message_id().get(), string(), 0,
is_closed),
top_thread_message_id_.get_server_message_id().get(), string(), 0,
is_closed, false),
{{channel_id}}));
}
void send(ChannelId channel_id, bool is_hidden) {
channel_id_ = channel_id;
top_thread_message_id_ = MessageId(ServerMessageId(1));
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
CHECK(input_channel != nullptr);
int32 flags = telegram_api::channels_editForumTopic::HIDDEN_MASK;
send_query(G()->net_query_creator().create(
telegram_api::channels_editForumTopic(flags, std::move(input_channel),
top_thread_message_id_.get_server_message_id().get(), string(), 0, false,
is_hidden),
{{channel_id}}));
}
@ -170,6 +201,175 @@ class EditForumTopicQuery final : public Td::ResultHandler {
}
};
class GetForumTopicQuery final : public Td::ResultHandler {
Promise<td_api::object_ptr<td_api::forumTopic>> promise_;
ChannelId channel_id_;
MessageId top_thread_message_id_;
public:
explicit GetForumTopicQuery(Promise<td_api::object_ptr<td_api::forumTopic>> &&promise)
: promise_(std::move(promise)) {
}
void send(ChannelId channel_id, MessageId top_thread_message_id) {
channel_id_ = channel_id;
top_thread_message_id_ = top_thread_message_id;
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
CHECK(input_channel != nullptr);
send_query(G()->net_query_creator().create(
telegram_api::channels_getForumTopicsByID(std::move(input_channel),
{top_thread_message_id_.get_server_message_id().get()}),
{{channel_id}}));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::channels_getForumTopicsByID>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for GetForumTopicQuery: " << to_string(ptr);
td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetForumTopicQuery");
td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetForumTopicQuery");
if (ptr->topics_.size() != 1u) {
return promise_.set_value(nullptr);
}
MessagesInfo messages_info;
messages_info.messages = std::move(ptr->messages_);
messages_info.total_count = ptr->count_;
messages_info.is_channel_messages = true;
td_->messages_manager_->get_channel_difference_if_needed(
DialogId(channel_id_), std::move(messages_info),
PromiseCreator::lambda([actor_id = td_->forum_topic_manager_actor_.get(), channel_id = channel_id_,
top_thread_message_id = top_thread_message_id_, topic = std::move(ptr->topics_[0]),
promise = std::move(promise_)](Result<MessagesInfo> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
auto info = result.move_as_ok();
send_closure(actor_id, &ForumTopicManager::on_get_forum_topic, channel_id, top_thread_message_id,
std::move(info), std::move(topic), std::move(promise));
}
}));
}
void on_error(Status status) final {
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "GetForumTopicQuery");
promise_.set_error(std::move(status));
}
};
class GetForumTopicsQuery final : public Td::ResultHandler {
Promise<td_api::object_ptr<td_api::forumTopics>> promise_;
ChannelId channel_id_;
public:
explicit GetForumTopicsQuery(Promise<td_api::object_ptr<td_api::forumTopics>> &&promise)
: promise_(std::move(promise)) {
}
void send(ChannelId channel_id, const string &query, int32 offset_date, MessageId offset_message_id,
MessageId offset_top_thread_message_id, int32 limit) {
channel_id_ = channel_id;
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
CHECK(input_channel != nullptr);
int32 flags = 0;
if (!query.empty()) {
flags |= telegram_api::channels_getForumTopics::Q_MASK;
}
send_query(G()->net_query_creator().create(
telegram_api::channels_getForumTopics(flags, std::move(input_channel), query, offset_date,
offset_message_id.get_server_message_id().get(),
offset_top_thread_message_id.get_server_message_id().get(), limit),
{{channel_id}}));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::channels_getForumTopics>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for GetForumTopicsQuery: " << to_string(ptr);
td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetForumTopicsQuery");
td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetForumTopicsQuery");
MessagesInfo messages_info;
messages_info.messages = std::move(ptr->messages_);
messages_info.total_count = ptr->count_;
messages_info.is_channel_messages = true;
// ignore ptr->pts_
td_->messages_manager_->get_channel_difference_if_needed(
DialogId(channel_id_), std::move(messages_info),
PromiseCreator::lambda([actor_id = td_->forum_topic_manager_actor_.get(), channel_id = channel_id_,
order_by_creation_date = ptr->order_by_create_date_, topics = std::move(ptr->topics_),
promise = std::move(promise_)](Result<MessagesInfo> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
auto info = result.move_as_ok();
send_closure(actor_id, &ForumTopicManager::on_get_forum_topics, channel_id, order_by_creation_date,
std::move(info), std::move(topics), std::move(promise));
}
}));
}
void on_error(Status status) final {
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "GetForumTopicsQuery");
promise_.set_error(std::move(status));
}
};
template <class StorerT>
void ForumTopicManager::Topic::store(StorerT &storer) const {
CHECK(info_ != nullptr);
using td::store;
store(MAGIC, storer);
bool has_topic = topic_ != nullptr;
BEGIN_STORE_FLAGS();
STORE_FLAG(has_topic);
END_STORE_FLAGS();
store(info_, storer);
if (has_topic) {
store(topic_, storer);
}
}
template <class ParserT>
void ForumTopicManager::Topic::parse(ParserT &parser) {
CHECK(info_ != nullptr);
using td::parse;
int32 magic;
parse(magic, parser);
if (magic != MAGIC) {
return parser.set_error("Invalid magic");
}
bool has_topic;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(has_topic);
END_PARSE_FLAGS();
parse(info_, parser);
if (has_topic) {
parse(topic_, parser);
}
}
ForumTopicManager::ForumTopicManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
}
@ -216,20 +416,26 @@ void ForumTopicManager::on_forum_topic_created(DialogId dialog_id, unique_ptr<Fo
Promise<td_api::object_ptr<td_api::forumTopicInfo>> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
auto topic_info = add_topic_info(dialog_id, std::move(forum_topic_info));
CHECK(topic_info != nullptr);
promise.set_value(topic_info->get_forum_topic_info_object(td_));
CHECK(forum_topic_info != nullptr);
MessageId top_thread_message_id = forum_topic_info->get_top_thread_message_id();
auto topic = add_topic(dialog_id, top_thread_message_id);
if (topic == nullptr) {
return promise.set_value(forum_topic_info->get_forum_topic_info_object(td_));
}
if (topic->info_ == nullptr) {
set_topic_info(dialog_id, topic, std::move(forum_topic_info));
}
save_topic_to_database(dialog_id, topic);
promise.set_value(topic->info_->get_forum_topic_info_object(td_));
}
void ForumTopicManager::edit_forum_topic(DialogId dialog_id, MessageId top_thread_message_id, string &&title,
CustomEmojiId icon_custom_emoji_id, Promise<Unit> &&promise) {
bool edit_icon_custom_emoji, CustomEmojiId icon_custom_emoji_id,
Promise<Unit> &&promise) {
TRY_STATUS_PROMISE(promise, is_forum(dialog_id));
TRY_STATUS_PROMISE(promise, can_be_message_thread_id(top_thread_message_id));
auto channel_id = dialog_id.get_channel_id();
if (!top_thread_message_id.is_valid() || !top_thread_message_id.is_server()) {
return promise.set_error(Status::Error(400, "Invalid message thread identifier specified"));
}
if (!td_->contacts_manager_->get_channel_permissions(channel_id).can_edit_topics()) {
auto topic_info = get_topic_info(dialog_id, top_thread_message_id);
if (topic_info != nullptr && !topic_info->is_outgoing()) {
@ -237,24 +443,213 @@ void ForumTopicManager::edit_forum_topic(DialogId dialog_id, MessageId top_threa
}
}
bool edit_title = !title.empty();
auto new_title = clean_name(std::move(title), MAX_FORUM_TOPIC_TITLE_LENGTH);
if (new_title.empty()) {
if (edit_title && new_title.empty()) {
return promise.set_error(Status::Error(400, "Title must be non-empty"));
}
if (!edit_title && !edit_icon_custom_emoji) {
return promise.set_value(Unit());
}
td_->create_handler<EditForumTopicQuery>(std::move(promise))
->send(channel_id, top_thread_message_id, new_title, icon_custom_emoji_id);
->send(channel_id, top_thread_message_id, edit_title, new_title, edit_icon_custom_emoji, icon_custom_emoji_id);
}
DialogNotificationSettings *ForumTopicManager::get_forum_topic_notification_settings(DialogId dialog_id,
MessageId top_thread_message_id) {
auto topic = get_topic(dialog_id, top_thread_message_id);
if (topic == nullptr || topic->topic_ == nullptr) {
return nullptr;
}
return topic->topic_->get_notification_settings();
}
const DialogNotificationSettings *ForumTopicManager::get_forum_topic_notification_settings(
DialogId dialog_id, MessageId top_thread_message_id) const {
auto topic = get_topic(dialog_id, top_thread_message_id);
if (topic == nullptr || topic->topic_ == nullptr) {
return nullptr;
}
return topic->topic_->get_notification_settings();
}
void ForumTopicManager::on_update_forum_topic_notify_settings(
DialogId dialog_id, MessageId top_thread_message_id,
tl_object_ptr<telegram_api::peerNotifySettings> &&peer_notify_settings, const char *source) {
if (td_->auth_manager_->is_bot()) {
return;
}
VLOG(notifications) << "Receive notification settings for topic of " << top_thread_message_id << " in " << dialog_id
<< " from " << source << ": " << to_string(peer_notify_settings);
DialogNotificationSettings *current_settings =
get_forum_topic_notification_settings(dialog_id, top_thread_message_id);
if (current_settings == nullptr) {
return;
}
auto notification_settings = get_dialog_notification_settings(std::move(peer_notify_settings), current_settings);
if (!notification_settings.is_synchronized) {
return;
}
update_forum_topic_notification_settings(dialog_id, top_thread_message_id, current_settings,
std::move(notification_settings));
}
Status ForumTopicManager::set_forum_topic_notification_settings(
DialogId dialog_id, MessageId top_thread_message_id,
tl_object_ptr<td_api::chatNotificationSettings> &&notification_settings) {
CHECK(!td_->auth_manager_->is_bot());
TRY_STATUS(is_forum(dialog_id));
TRY_STATUS(can_be_message_thread_id(top_thread_message_id));
auto current_settings = get_forum_topic_notification_settings(dialog_id, top_thread_message_id);
if (current_settings == nullptr) {
return Status::Error(400, "Unknown forum topic identifier specified");
}
TRY_RESULT(new_settings, get_dialog_notification_settings(std::move(notification_settings), current_settings));
if (update_forum_topic_notification_settings(dialog_id, top_thread_message_id, current_settings,
std::move(new_settings))) {
// TODO log event
td_->notification_settings_manager_->update_dialog_notify_settings(dialog_id, top_thread_message_id,
*current_settings, Promise<Unit>());
}
return Status::OK();
}
bool ForumTopicManager::update_forum_topic_notification_settings(DialogId dialog_id, MessageId top_thread_message_id,
DialogNotificationSettings *current_settings,
DialogNotificationSettings &&new_settings) {
if (td_->auth_manager_->is_bot()) {
// just in case
return false;
}
auto need_update = need_update_dialog_notification_settings(current_settings, new_settings);
if (need_update.are_changed) {
// TODO update unmute timeouts, td_api updates, remove notifications
*current_settings = std::move(new_settings);
auto topic = get_topic(dialog_id, top_thread_message_id);
CHECK(topic != nullptr);
topic->need_save_to_database_ = true;
save_topic_to_database(dialog_id, topic);
}
return need_update.need_update_server;
}
void ForumTopicManager::get_forum_topic(DialogId dialog_id, MessageId top_thread_message_id,
Promise<td_api::object_ptr<td_api::forumTopic>> &&promise) {
TRY_STATUS_PROMISE(promise, is_forum(dialog_id));
TRY_STATUS_PROMISE(promise, can_be_message_thread_id(top_thread_message_id));
auto channel_id = dialog_id.get_channel_id();
td_->create_handler<GetForumTopicQuery>(std::move(promise))->send(channel_id, top_thread_message_id);
}
void ForumTopicManager::on_get_forum_topic(ChannelId channel_id, MessageId expected_top_thread_message_id,
MessagesInfo &&info,
telegram_api::object_ptr<telegram_api::ForumTopic> &&topic,
Promise<td_api::object_ptr<td_api::forumTopic>> &&promise) {
DialogId dialog_id(channel_id);
TRY_STATUS_PROMISE(promise, is_forum(dialog_id));
td_->messages_manager_->on_get_messages(std::move(info.messages), true, false, Promise<Unit>(), "on_get_forum_topic");
auto top_thread_message_id = on_get_forum_topic_impl(dialog_id, std::move(topic));
if (!top_thread_message_id.is_valid()) {
return promise.set_value(nullptr);
}
if (top_thread_message_id != expected_top_thread_message_id) {
return promise.set_error(Status::Error(500, "Wrong forum topic received"));
}
promise.set_value(get_forum_topic_object(dialog_id, top_thread_message_id));
}
void ForumTopicManager::get_forum_topic_link(DialogId dialog_id, MessageId top_thread_message_id,
Promise<string> &&promise) {
TRY_STATUS_PROMISE(promise, is_forum(dialog_id));
TRY_STATUS_PROMISE(promise, can_be_message_thread_id(top_thread_message_id));
auto channel_id = dialog_id.get_channel_id();
SliceBuilder sb;
sb << td_->option_manager_->get_option_string("t_me_url", "https://t.me/");
auto dialog_username = td_->contacts_manager_->get_channel_first_username(channel_id);
if (!dialog_username.empty()) {
sb << dialog_username;
} else {
sb << "c/" << channel_id.get();
}
sb << '/' << top_thread_message_id.get_server_message_id().get();
promise.set_value(sb.as_cslice().str());
}
void ForumTopicManager::get_forum_topics(DialogId dialog_id, string query, int32 offset_date,
MessageId offset_message_id, MessageId offset_top_thread_message_id,
int32 limit, Promise<td_api::object_ptr<td_api::forumTopics>> promise) {
TRY_STATUS_PROMISE(promise, is_forum(dialog_id));
auto channel_id = dialog_id.get_channel_id();
if (offset_date < 0) {
return promise.set_error(Status::Error(400, "Invalid offset date specified"));
}
if (offset_message_id != MessageId() && !offset_message_id.is_valid() && !offset_message_id.is_server()) {
return promise.set_error(Status::Error(400, "Invalid offset message identifier specified"));
}
if (offset_top_thread_message_id != MessageId()) {
TRY_STATUS_PROMISE(promise, can_be_message_thread_id(offset_top_thread_message_id));
}
if (limit <= 0) {
return promise.set_error(Status::Error(400, "Invalid limit specified"));
}
td_->create_handler<GetForumTopicsQuery>(std::move(promise))
->send(channel_id, query, offset_date, offset_message_id, offset_top_thread_message_id, limit);
}
void ForumTopicManager::on_get_forum_topics(ChannelId channel_id, bool order_by_creation_date, MessagesInfo &&info,
vector<telegram_api::object_ptr<telegram_api::ForumTopic>> &&topics,
Promise<td_api::object_ptr<td_api::forumTopics>> &&promise) {
DialogId dialog_id(channel_id);
TRY_STATUS_PROMISE(promise, is_forum(dialog_id));
td_->messages_manager_->on_get_messages(std::move(info.messages), true, false, Promise<Unit>(),
"on_get_forum_topics");
vector<td_api::object_ptr<td_api::forumTopic>> forum_topics;
int32 next_offset_date = 0;
MessageId next_offset_message_id;
MessageId next_offset_top_thread_message_id;
for (auto &topic : topics) {
auto top_thread_message_id = on_get_forum_topic_impl(dialog_id, std::move(topic));
if (!top_thread_message_id.is_valid()) {
continue;
}
auto forum_topic_object = get_forum_topic_object(dialog_id, top_thread_message_id);
CHECK(forum_topic_object != nullptr);
if (order_by_creation_date || forum_topic_object->last_message_ == nullptr) {
next_offset_date = forum_topic_object->info_->creation_date_;
} else {
next_offset_date = forum_topic_object->last_message_->date_;
}
next_offset_message_id =
forum_topic_object->last_message_ != nullptr ? MessageId(forum_topic_object->last_message_->id_) : MessageId();
next_offset_top_thread_message_id = top_thread_message_id;
forum_topics.push_back(std::move(forum_topic_object));
}
promise.set_value(td_api::make_object<td_api::forumTopics>(info.total_count, std::move(forum_topics),
next_offset_date, next_offset_message_id.get(),
next_offset_top_thread_message_id.get()));
}
void ForumTopicManager::toggle_forum_topic_is_closed(DialogId dialog_id, MessageId top_thread_message_id,
bool is_closed, Promise<Unit> &&promise) {
TRY_STATUS_PROMISE(promise, is_forum(dialog_id));
TRY_STATUS_PROMISE(promise, can_be_message_thread_id(top_thread_message_id));
auto channel_id = dialog_id.get_channel_id();
if (!top_thread_message_id.is_valid() || !top_thread_message_id.is_server()) {
return promise.set_error(Status::Error(400, "Invalid message thread identifier specified"));
}
if (!td_->contacts_manager_->get_channel_permissions(channel_id).can_edit_topics()) {
auto topic_info = get_topic_info(dialog_id, top_thread_message_id);
if (topic_info != nullptr && !topic_info->is_outgoing()) {
@ -265,15 +660,23 @@ void ForumTopicManager::toggle_forum_topic_is_closed(DialogId dialog_id, Message
td_->create_handler<EditForumTopicQuery>(std::move(promise))->send(channel_id, top_thread_message_id, is_closed);
}
void ForumTopicManager::delete_forum_topic(DialogId dialog_id, MessageId top_thread_message_id,
Promise<Unit> &&promise) {
void ForumTopicManager::toggle_forum_topic_is_hidden(DialogId dialog_id, bool is_hidden, Promise<Unit> &&promise) {
TRY_STATUS_PROMISE(promise, is_forum(dialog_id));
auto channel_id = dialog_id.get_channel_id();
if (!top_thread_message_id.is_valid() || !top_thread_message_id.is_server()) {
return promise.set_error(Status::Error(400, "Invalid message thread identifier specified"));
if (!td_->contacts_manager_->get_channel_permissions(channel_id).can_edit_topics()) {
return promise.set_error(Status::Error(400, "Not enough rights to close or open the topic"));
}
td_->create_handler<EditForumTopicQuery>(std::move(promise))->send(channel_id, is_hidden);
}
void ForumTopicManager::delete_forum_topic(DialogId dialog_id, MessageId top_thread_message_id,
Promise<Unit> &&promise) {
TRY_STATUS_PROMISE(promise, is_forum(dialog_id));
TRY_STATUS_PROMISE(promise, can_be_message_thread_id(top_thread_message_id));
auto channel_id = dialog_id.get_channel_id();
if (!td_->contacts_manager_->get_channel_permissions(channel_id).can_delete_messages()) {
auto topic_info = get_topic_info(dialog_id, top_thread_message_id);
if (topic_info != nullptr && !topic_info->is_outgoing()) {
@ -281,18 +684,150 @@ void ForumTopicManager::delete_forum_topic(DialogId dialog_id, MessageId top_thr
}
}
td_->messages_manager_->delete_topic_history(dialog_id, top_thread_message_id, std::move(promise));
auto delete_promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, top_thread_message_id,
promise = std::move(promise)](Result<Unit> result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
send_closure(actor_id, &ForumTopicManager::on_delete_forum_topic, dialog_id, top_thread_message_id,
std::move(promise));
});
td_->messages_manager_->delete_topic_history(dialog_id, top_thread_message_id, std::move(delete_promise));
}
void ForumTopicManager::on_delete_forum_topic(DialogId dialog_id, MessageId top_thread_message_id,
Promise<Unit> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
auto *dialog_topics = dialog_topics_.get_pointer(dialog_id);
if (dialog_topics != nullptr) {
dialog_topics->topics_.erase(top_thread_message_id);
dialog_topics->deleted_topic_ids_.insert(top_thread_message_id);
}
delete_topic_from_database(dialog_id, top_thread_message_id, std::move(promise));
}
void ForumTopicManager::delete_all_dialog_topics(DialogId dialog_id) {
dialog_topics_.erase(dialog_id);
auto message_thread_db = G()->td_db()->get_message_thread_db_async();
if (message_thread_db == nullptr) {
return;
}
LOG(INFO) << "Delete all topics in " << dialog_id << " from database";
message_thread_db->delete_all_dialog_message_threads(dialog_id, Auto());
}
void ForumTopicManager::on_forum_topic_edited(DialogId dialog_id, MessageId top_thread_message_id,
const ForumTopicEditedData &edited_data) {
auto topic_info = get_topic_info(dialog_id, top_thread_message_id);
if (topic_info == nullptr) {
auto topic = get_topic(dialog_id, top_thread_message_id);
if (topic == nullptr || topic->info_ == nullptr) {
return;
}
if (topic_info->apply_edited_data(edited_data)) {
send_update_forum_topic_info(dialog_id, topic_info);
if (topic->info_->apply_edited_data(edited_data)) {
send_update_forum_topic_info(dialog_id, topic->info_.get());
topic->need_save_to_database_ = true;
}
save_topic_to_database(dialog_id, topic);
}
void ForumTopicManager::on_get_forum_topic_info(DialogId dialog_id, const ForumTopicInfo &topic_info,
const char *source) {
if (!can_be_forum(dialog_id)) {
LOG(ERROR) << "Receive forum topics in " << dialog_id << " from " << source;
return;
}
auto dialog_topics = add_dialog_topics(dialog_id);
CHECK(dialog_topics != nullptr);
auto forum_topic_info = td::make_unique<ForumTopicInfo>(topic_info);
MessageId top_thread_message_id = forum_topic_info->get_top_thread_message_id();
CHECK(can_be_message_thread_id(top_thread_message_id).is_ok());
auto topic = add_topic(dialog_topics, top_thread_message_id);
if (topic == nullptr) {
return;
}
set_topic_info(dialog_id, topic, std::move(forum_topic_info));
save_topic_to_database(dialog_id, topic);
}
void ForumTopicManager::on_get_forum_topic_infos(DialogId dialog_id,
vector<tl_object_ptr<telegram_api::ForumTopic>> &&forum_topics,
const char *source) {
if (forum_topics.empty()) {
return;
}
if (!can_be_forum(dialog_id)) {
LOG(ERROR) << "Receive forum topics in " << dialog_id << " from " << source;
return;
}
auto dialog_topics = add_dialog_topics(dialog_id);
CHECK(dialog_topics != nullptr);
for (auto &forum_topic : forum_topics) {
auto forum_topic_info = td::make_unique<ForumTopicInfo>(forum_topic);
MessageId top_thread_message_id = forum_topic_info->get_top_thread_message_id();
if (can_be_message_thread_id(top_thread_message_id).is_error()) {
continue;
}
auto topic = add_topic(dialog_topics, top_thread_message_id);
if (topic != nullptr) {
set_topic_info(dialog_id, topic, std::move(forum_topic_info));
save_topic_to_database(dialog_id, topic);
}
}
}
MessageId ForumTopicManager::on_get_forum_topic_impl(DialogId dialog_id,
tl_object_ptr<telegram_api::ForumTopic> &&forum_topic) {
CHECK(forum_topic != nullptr);
switch (forum_topic->get_id()) {
case telegram_api::forumTopicDeleted::ID: {
auto top_thread_message_id =
MessageId(ServerMessageId(static_cast<const telegram_api::forumTopicDeleted *>(forum_topic.get())->id_));
if (!top_thread_message_id.is_valid()) {
LOG(ERROR) << "Receive " << to_string(forum_topic);
return MessageId();
}
on_delete_forum_topic(dialog_id, top_thread_message_id, Promise<Unit>());
return MessageId();
}
case telegram_api::forumTopic::ID: {
auto forum_topic_info = td::make_unique<ForumTopicInfo>(forum_topic);
MessageId top_thread_message_id = forum_topic_info->get_top_thread_message_id();
Topic *topic = add_topic(dialog_id, top_thread_message_id);
if (topic == nullptr) {
return MessageId();
}
auto current_notification_settings =
topic->topic_ == nullptr ? nullptr : topic->topic_->get_notification_settings();
auto forum_topic_full = td::make_unique<ForumTopic>(td_, std::move(forum_topic), current_notification_settings);
if (forum_topic_full->is_short()) {
LOG(ERROR) << "Receive short " << to_string(forum_topic);
return MessageId();
}
if (topic->topic_ == nullptr || true) {
topic->topic_ = std::move(forum_topic_full);
topic->need_save_to_database_ = true; // temporary
}
set_topic_info(dialog_id, topic, std::move(forum_topic_info));
save_topic_to_database(dialog_id, topic);
return top_thread_message_id;
}
default:
UNREACHABLE();
return MessageId();
}
}
td_api::object_ptr<td_api::forumTopic> ForumTopicManager::get_forum_topic_object(
DialogId dialog_id, MessageId top_thread_message_id) const {
auto topic = get_topic(dialog_id, top_thread_message_id);
if (topic == nullptr || topic->topic_ == nullptr) {
return nullptr;
}
CHECK(topic->info_ != nullptr);
return topic->topic_->get_forum_topic_object(td_, dialog_id, *topic->info_);
}
Status ForumTopicManager::is_forum(DialogId dialog_id) {
@ -306,40 +841,84 @@ Status ForumTopicManager::is_forum(DialogId dialog_id) {
return Status::OK();
}
ForumTopicInfo *ForumTopicManager::add_topic_info(DialogId dialog_id, unique_ptr<ForumTopicInfo> &&forum_topic_info) {
CHECK(forum_topic_info != nullptr);
auto *dialog_info = dialog_topics_.get_pointer(dialog_id);
if (dialog_info == nullptr) {
dialog_topics_.set(dialog_id, make_unique<DialogTopics>());
dialog_info = dialog_topics_.get_pointer(dialog_id);
CHECK(dialog_info != nullptr);
}
bool ForumTopicManager::can_be_forum(DialogId dialog_id) const {
return dialog_id.get_type() == DialogType::Channel &&
td_->contacts_manager_->is_megagroup_channel(dialog_id.get_channel_id());
}
MessageId top_thread_message_id = forum_topic_info->get_top_thread_message_id();
auto topic_info = dialog_info->topic_infos_.get_pointer(top_thread_message_id);
if (topic_info == nullptr) {
dialog_info->topic_infos_.set(top_thread_message_id, std::move(forum_topic_info));
topic_info = get_topic_info(dialog_id, top_thread_message_id);
CHECK(topic_info != nullptr);
send_update_forum_topic_info(dialog_id, topic_info);
Status ForumTopicManager::can_be_message_thread_id(MessageId top_thread_message_id) {
if (!top_thread_message_id.is_valid() || !top_thread_message_id.is_server()) {
return Status::Error(400, "Invalid message thread identifier specified");
}
return topic_info;
return Status::OK();
}
ForumTopicManager::DialogTopics *ForumTopicManager::add_dialog_topics(DialogId dialog_id) {
auto *dialog_topics = dialog_topics_.get_pointer(dialog_id);
if (dialog_topics == nullptr) {
auto new_dialog_topics = make_unique<DialogTopics>();
dialog_topics = new_dialog_topics.get();
dialog_topics_.set(dialog_id, std::move(new_dialog_topics));
}
return dialog_topics;
}
ForumTopicManager::Topic *ForumTopicManager::add_topic(DialogTopics *dialog_topics, MessageId top_thread_message_id) {
auto topic = dialog_topics->topics_.get_pointer(top_thread_message_id);
if (topic == nullptr) {
if (dialog_topics->deleted_topic_ids_.count(top_thread_message_id) > 0) {
return nullptr;
}
auto new_topic = make_unique<Topic>();
topic = new_topic.get();
dialog_topics->topics_.set(top_thread_message_id, std::move(new_topic));
}
return topic;
}
ForumTopicManager::Topic *ForumTopicManager::add_topic(DialogId dialog_id, MessageId top_thread_message_id) {
return add_topic(add_dialog_topics(dialog_id), top_thread_message_id);
}
ForumTopicManager::Topic *ForumTopicManager::get_topic(DialogId dialog_id, MessageId top_thread_message_id) {
auto *dialog_topics = dialog_topics_.get_pointer(dialog_id);
if (dialog_topics == nullptr) {
return nullptr;
}
return dialog_topics->topics_.get_pointer(top_thread_message_id);
}
const ForumTopicManager::Topic *ForumTopicManager::get_topic(DialogId dialog_id,
MessageId top_thread_message_id) const {
auto *dialog_topics = dialog_topics_.get_pointer(dialog_id);
if (dialog_topics == nullptr) {
return nullptr;
}
return dialog_topics->topics_.get_pointer(top_thread_message_id);
}
ForumTopicInfo *ForumTopicManager::get_topic_info(DialogId dialog_id, MessageId top_thread_message_id) {
auto *dialog_info = dialog_topics_.get_pointer(dialog_id);
if (dialog_info == nullptr) {
auto *topic = get_topic(dialog_id, top_thread_message_id);
if (topic == nullptr) {
return nullptr;
}
return dialog_info->topic_infos_.get_pointer(top_thread_message_id);
return topic->info_.get();
}
const ForumTopicInfo *ForumTopicManager::get_topic_info(DialogId dialog_id, MessageId top_thread_message_id) const {
auto *dialog_info = dialog_topics_.get_pointer(dialog_id);
if (dialog_info == nullptr) {
auto *topic = get_topic(dialog_id, top_thread_message_id);
if (topic == nullptr) {
return nullptr;
}
return dialog_info->topic_infos_.get_pointer(top_thread_message_id);
return topic->info_.get();
}
void ForumTopicManager::set_topic_info(DialogId dialog_id, Topic *topic, unique_ptr<ForumTopicInfo> forum_topic_info) {
if (topic->info_ == nullptr || *topic->info_ != *forum_topic_info) {
topic->info_ = std::move(forum_topic_info);
send_update_forum_topic_info(dialog_id, topic->info_.get());
topic->need_save_to_database_ = true;
}
}
td_api::object_ptr<td_api::updateForumTopicInfo> ForumTopicManager::get_update_forum_topic_info(
@ -355,4 +934,54 @@ void ForumTopicManager::send_update_forum_topic_info(DialogId dialog_id, const F
send_closure(G()->td(), &Td::send_update, get_update_forum_topic_info(dialog_id, topic_info));
}
void ForumTopicManager::save_topic_to_database(DialogId dialog_id, const Topic *topic) {
CHECK(topic != nullptr);
if (topic->info_ == nullptr || !topic->need_save_to_database_) {
return;
}
topic->need_save_to_database_ = false;
auto message_thread_db = G()->td_db()->get_message_thread_db_async();
if (message_thread_db == nullptr) {
return;
}
auto top_thread_message_id = topic->info_->get_top_thread_message_id();
LOG(INFO) << "Save topic of " << top_thread_message_id << " in " << dialog_id << " to database";
message_thread_db->add_message_thread(dialog_id, top_thread_message_id, 0, log_event_store(*topic), Auto());
}
void ForumTopicManager::delete_topic_from_database(DialogId dialog_id, MessageId top_thread_message_id,
Promise<Unit> &&promise) {
auto message_thread_db = G()->td_db()->get_message_thread_db_async();
if (message_thread_db == nullptr) {
return promise.set_value(Unit());
}
LOG(INFO) << "Delete topic of " << top_thread_message_id << " in " << dialog_id << " from database";
message_thread_db->delete_message_thread(dialog_id, top_thread_message_id, std::move(promise));
}
void ForumTopicManager::on_topic_message_count_changed(DialogId dialog_id, MessageId top_thread_message_id, int diff) {
if (!can_be_forum(dialog_id) || can_be_message_thread_id(top_thread_message_id).is_error()) {
LOG(ERROR) << "Change by " << diff << " number of loaded messages in thread of " << top_thread_message_id << " in "
<< dialog_id;
return;
}
LOG(INFO) << "Change by " << diff << " number of loaded messages in thread of " << top_thread_message_id << " in "
<< dialog_id;
auto dialog_topics = add_dialog_topics(dialog_id);
auto topic = add_topic(dialog_topics, top_thread_message_id);
if (topic == nullptr) {
return;
}
topic->message_count_ += diff;
CHECK(topic->message_count_ >= 0);
if (topic->message_count_ == 0) {
// TODO keep topics in the topic list
dialog_topics->topics_.erase(top_thread_message_id);
}
}
} // namespace td

View File

@ -6,12 +6,17 @@
//
#pragma once
#include "td/telegram/ChannelId.h"
#include "td/telegram/CustomEmojiId.h"
#include "td/telegram/DialogId.h"
#include "td/telegram/DialogNotificationSettings.h"
#include "td/telegram/ForumTopic.h"
#include "td/telegram/ForumTopicEditedData.h"
#include "td/telegram/ForumTopicInfo.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/MessagesInfo.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/actor/actor.h"
@ -19,6 +24,7 @@
#include "td/utils/Promise.h"
#include "td/utils/Status.h"
#include "td/utils/WaitFreeHashMap.h"
#include "td/utils/WaitFreeHashSet.h"
namespace td {
@ -40,38 +46,125 @@ class ForumTopicManager final : public Actor {
Promise<td_api::object_ptr<td_api::forumTopicInfo>> &&promise);
void edit_forum_topic(DialogId dialog_id, MessageId top_thread_message_id, string &&title,
CustomEmojiId icon_custom_emoji_id, Promise<Unit> &&promise);
bool edit_icon_custom_emoji, CustomEmojiId icon_custom_emoji_id, Promise<Unit> &&promise);
void get_forum_topic(DialogId dialog_id, MessageId top_thread_message_id,
Promise<td_api::object_ptr<td_api::forumTopic>> &&promise);
void on_get_forum_topic(ChannelId channel_id, MessageId expected_top_thread_message_id, MessagesInfo &&info,
telegram_api::object_ptr<telegram_api::ForumTopic> &&topic,
Promise<td_api::object_ptr<td_api::forumTopic>> &&promise);
void on_get_forum_topics(ChannelId channel_id, bool order_by_creation_date, MessagesInfo &&info,
vector<telegram_api::object_ptr<telegram_api::ForumTopic>> &&topics,
Promise<td_api::object_ptr<td_api::forumTopics>> &&promise);
void get_forum_topic_link(DialogId dialog_id, MessageId top_thread_message_id, Promise<string> &&promise);
void get_forum_topics(DialogId dialog_id, string query, int32 offset_date, MessageId offset_message_id,
MessageId offset_top_thread_message_id, int32 limit,
Promise<td_api::object_ptr<td_api::forumTopics>> promise);
void toggle_forum_topic_is_closed(DialogId dialog_id, MessageId top_thread_message_id, bool is_closed,
Promise<Unit> &&promise);
const DialogNotificationSettings *get_forum_topic_notification_settings(DialogId dialog_id,
MessageId top_thread_message_id) const;
Status set_forum_topic_notification_settings(DialogId dialog_id, MessageId top_thread_message_id,
tl_object_ptr<td_api::chatNotificationSettings> &&notification_settings)
TD_WARN_UNUSED_RESULT;
void toggle_forum_topic_is_hidden(DialogId dialog_id, bool is_hidden, Promise<Unit> &&promise);
void delete_forum_topic(DialogId dialog_id, MessageId top_thread_message_id, Promise<Unit> &&promise);
void delete_all_dialog_topics(DialogId dialog_id);
void on_update_forum_topic_notify_settings(DialogId dialog_id, MessageId top_thread_message_id,
tl_object_ptr<telegram_api::peerNotifySettings> &&peer_notify_settings,
const char *source);
void on_forum_topic_edited(DialogId dialog_id, MessageId top_thread_message_id,
const ForumTopicEditedData &edited_data);
void on_get_forum_topic_info(DialogId dialog_id, const ForumTopicInfo &topic_info, const char *source);
void on_get_forum_topic_infos(DialogId dialog_id, vector<tl_object_ptr<telegram_api::ForumTopic>> &&forum_topics,
const char *source);
td_api::object_ptr<td_api::forumTopic> get_forum_topic_object(DialogId dialog_id,
MessageId top_thread_message_id) const;
void on_topic_message_count_changed(DialogId dialog_id, MessageId top_thread_message_id, int diff);
private:
static constexpr size_t MAX_FORUM_TOPIC_TITLE_LENGTH = 128; // server side limit for forum topic title
struct Topic {
unique_ptr<ForumTopicInfo> info_;
unique_ptr<ForumTopic> topic_;
int32 message_count_ = 0;
mutable bool need_save_to_database_ = true;
template <class StorerT>
void store(StorerT &storer) const;
template <class ParserT>
void parse(ParserT &parser);
int32 MAGIC = 0x1fac3901;
};
struct DialogTopics {
WaitFreeHashMap<MessageId, unique_ptr<ForumTopicInfo>, MessageIdHash> topic_infos_;
WaitFreeHashMap<MessageId, unique_ptr<Topic>, MessageIdHash> topics_;
WaitFreeHashSet<MessageId, MessageIdHash> deleted_topic_ids_;
};
void tear_down() final;
Status is_forum(DialogId dialog_id);
ForumTopicInfo *add_topic_info(DialogId dialog_id, unique_ptr<ForumTopicInfo> &&forum_topic_info);
bool can_be_forum(DialogId dialog_id) const;
static Status can_be_message_thread_id(MessageId top_thread_message_id);
DialogTopics *add_dialog_topics(DialogId dialog_id);
static Topic *add_topic(DialogTopics *dialog_topics, MessageId top_thread_message_id);
Topic *add_topic(DialogId dialog_id, MessageId top_thread_message_id);
Topic *get_topic(DialogId dialog_id, MessageId top_thread_message_id);
const Topic *get_topic(DialogId dialog_id, MessageId top_thread_message_id) const;
ForumTopicInfo *get_topic_info(DialogId dialog_id, MessageId top_thread_message_id);
const ForumTopicInfo *get_topic_info(DialogId dialog_id, MessageId top_thread_message_id) const;
void set_topic_info(DialogId dialog_id, Topic *topic, unique_ptr<ForumTopicInfo> forum_topic_info);
MessageId on_get_forum_topic_impl(DialogId dialog_id, tl_object_ptr<telegram_api::ForumTopic> &&forum_topic);
DialogNotificationSettings *get_forum_topic_notification_settings(DialogId dialog_id,
MessageId top_thread_message_id);
bool update_forum_topic_notification_settings(DialogId dialog_id, MessageId top_thread_message_id,
DialogNotificationSettings *current_settings,
DialogNotificationSettings &&new_settings);
void on_delete_forum_topic(DialogId dialog_id, MessageId top_thread_message_id, Promise<Unit> &&promise);
td_api::object_ptr<td_api::updateForumTopicInfo> get_update_forum_topic_info(DialogId dialog_id,
const ForumTopicInfo *topic_info) const;
void send_update_forum_topic_info(DialogId dialog_id, const ForumTopicInfo *topic_info) const;
void save_topic_to_database(DialogId dialog_id, const Topic *topic);
void delete_topic_from_database(DialogId dialog_id, MessageId top_thread_message_id, Promise<Unit> &&promise);
Td *td_;
ActorShared<> parent_;

View File

@ -8,6 +8,7 @@
#include "td/telegram/DialogId.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/common.h"
#include "td/utils/StringBuilder.h"
@ -37,10 +38,15 @@ struct FullMessageId {
DialogId get_dialog_id() const {
return dialog_id;
}
MessageId get_message_id() const {
return message_id;
}
static FullMessageId get_full_message_id(const tl_object_ptr<telegram_api::Message> &message_ptr, bool is_scheduled) {
return {DialogId::get_message_dialog_id(message_ptr), MessageId::get_message_id(message_ptr, is_scheduled)};
}
template <class StorerT>
void store(StorerT &storer) const {
dialog_id.store(storer);

View File

@ -551,6 +551,18 @@ class LinkManager::InternalLinkUserPhoneNumber final : public InternalLink {
}
};
class LinkManager::InternalLinkUserToken final : public InternalLink {
string token_;
td_api::object_ptr<td_api::InternalLinkType> get_internal_link_type_object() const final {
return td_api::make_object<td_api::internalLinkTypeUserToken>(token_);
}
public:
explicit InternalLinkUserToken(string token) : token_(std::move(token)) {
}
};
class LinkManager::InternalLinkVoiceChat final : public InternalLink {
string dialog_username_;
string invite_hash_;
@ -1084,6 +1096,11 @@ unique_ptr<LinkManager::InternalLink> LinkManager::parse_tg_link_query(Slice que
// resolve?phone=12345
return std::move(user_link);
}
} else if (path.size() == 1 && path[0] == "contact") {
// contact?token=<token>
if (has_arg("token")) {
return td::make_unique<InternalLinkUserToken>(get_arg("token"));
}
} else if (path.size() == 1 && path[0] == "login") {
// login?code=123456
if (has_arg("code")) {
@ -1282,6 +1299,11 @@ unique_ptr<LinkManager::InternalLink> LinkManager::parse_t_me_link_query(Slice q
<< url_encode(get_url_query_hash(false, url_query)));
}
}
} else if (path[0] == "contact") {
if (path.size() >= 2 && !path[1].empty()) {
// /contact/<token>
return td::make_unique<InternalLinkUserToken>(path[1]);
}
} else if (path[0] == "addstickers" || path[0] == "addemoji") {
if (path.size() >= 2 && !path[1].empty()) {
// /addstickers/<name>
@ -1668,6 +1690,10 @@ string LinkManager::get_instant_view_link(Slice url, Slice rhash) {
<< "&rhash=" << url_encode(rhash);
}
string LinkManager::get_public_chat_link(Slice username) {
return PSTRING() << G()->get_option_string("t_me_url", "https://t.me/") << url_encode(username);
}
UserId LinkManager::get_link_user_id(Slice url) {
string lower_cased_url = to_lower(url);
url = lower_cased_url;

View File

@ -88,6 +88,8 @@ class LinkManager final : public Actor {
static string get_instant_view_link(Slice url, Slice rhash);
static string get_public_chat_link(Slice username);
static UserId get_link_user_id(Slice url);
static Result<CustomEmojiId> get_link_custom_emoji_id(Slice url);
@ -131,6 +133,7 @@ class LinkManager final : public Actor {
class InternalLinkUnknownDeepLink;
class InternalLinkUnsupportedProxy;
class InternalLinkUserPhoneNumber;
class InternalLinkUserToken;
class InternalLinkVoiceChat;
enum class LinkType : int32 { External, TMe, Tg, Telegraph };

View File

@ -450,9 +450,10 @@ class MessageScreenshotTaken final : public MessageContent {
class MessageChatSetTtl final : public MessageContent {
public:
int32 ttl;
UserId from_user_id;
MessageChatSetTtl() = default;
explicit MessageChatSetTtl(int32 ttl) : ttl(ttl) {
MessageChatSetTtl(int32 ttl, UserId from_user_id) : ttl(ttl), from_user_id(from_user_id) {
}
MessageContentType get_type() const final {
@ -462,7 +463,7 @@ class MessageChatSetTtl final : public MessageContent {
class MessageUnsupported final : public MessageContent {
public:
static constexpr int32 CURRENT_VERSION = 14;
static constexpr int32 CURRENT_VERSION = 15;
int32 version = CURRENT_VERSION;
MessageUnsupported() = default;
@ -1009,7 +1010,14 @@ static void store(const MessageContent *content, StorerT &storer) {
break;
case MessageContentType::ChatSetTtl: {
const auto *m = static_cast<const MessageChatSetTtl *>(content);
bool has_from_user_id = m->from_user_id.is_valid();
BEGIN_STORE_FLAGS();
STORE_FLAG(has_from_user_id);
END_STORE_FLAGS();
store(m->ttl, storer);
if (has_from_user_id) {
store(m->from_user_id, storer);
}
break;
}
case MessageContentType::Call: {
@ -1427,7 +1435,16 @@ static void parse(unique_ptr<MessageContent> &content, ParserT &parser) {
break;
case MessageContentType::ChatSetTtl: {
auto m = make_unique<MessageChatSetTtl>();
bool has_from_user_id = false;
if (parser.version() >= static_cast<int32>(Version::AddMessageChatSetTtlFlags)) {
BEGIN_PARSE_FLAGS();
PARSE_FLAG(has_from_user_id);
END_PARSE_FLAGS();
}
parse(m->ttl, parser);
if (has_from_user_id) {
parse(m->from_user_id, parser);
}
content = std::move(m);
break;
}
@ -1783,8 +1800,8 @@ unique_ptr<MessageContent> create_screenshot_taken_message_content() {
return make_unique<MessageScreenshotTaken>();
}
unique_ptr<MessageContent> create_chat_set_ttl_message_content(int32 ttl) {
return make_unique<MessageChatSetTtl>(ttl);
unique_ptr<MessageContent> create_chat_set_ttl_message_content(int32 ttl, UserId from_user_id) {
return make_unique<MessageChatSetTtl>(ttl, from_user_id);
}
static Result<InputMessageContent> create_input_message_content(
@ -3586,7 +3603,10 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo
const auto *old_ = static_cast<const MessageChatSetTtl *>(old_content);
const auto *new_ = static_cast<const MessageChatSetTtl *>(new_content);
if (old_->ttl != new_->ttl) {
LOG(ERROR) << "Ttl has changed from " << old_->ttl << " to " << new_->ttl;
LOG(ERROR) << "TTL has changed from " << old_->ttl << " to " << new_->ttl;
need_update = true;
}
if (old_->from_user_id != new_->from_user_id) {
need_update = true;
}
break;
@ -3594,10 +3614,11 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo
case MessageContentType::Call: {
const auto *old_ = static_cast<const MessageCall *>(old_content);
const auto *new_ = static_cast<const MessageCall *>(new_content);
if (old_->call_id != new_->call_id || old_->is_video != new_->is_video) {
if (old_->call_id != new_->call_id) {
is_content_changed = true;
}
if (old_->duration != new_->duration || old_->discard_reason != new_->discard_reason) {
if (old_->duration != new_->duration || old_->discard_reason != new_->discard_reason ||
old_->is_video != new_->is_video) {
need_update = true;
}
break;
@ -5131,11 +5152,12 @@ unique_ptr<MessageContent> get_action_message_content(Td *td, tl_object_ptr<tele
}
case telegram_api::messageActionSetMessagesTTL::ID: {
auto action = move_tl_object_as<telegram_api::messageActionSetMessagesTTL>(action_ptr);
if (action->period_ < 0) {
LOG(ERROR) << "Receive wrong TTL = " << action->period_;
UserId from_user_id(action->auto_setting_from_);
if (action->period_ < 0 || !(from_user_id == UserId() || from_user_id.is_valid())) {
LOG(ERROR) << "Receive invalid " << oneline(to_string(action));
break;
}
return make_unique<MessageChatSetTtl>(action->period_);
return make_unique<MessageChatSetTtl>(action->period_, from_user_id);
}
case telegram_api::messageActionGroupCallScheduled::ID: {
auto action = move_tl_object_as<telegram_api::messageActionGroupCallScheduled>(action_ptr);
@ -5184,9 +5206,10 @@ unique_ptr<MessageContent> get_action_message_content(Td *td, tl_object_ptr<tele
auto action = move_tl_object_as<telegram_api::messageActionTopicEdit>(action_ptr);
auto edit_icon_custom_emoji_id = (action->flags_ & telegram_api::messageActionTopicEdit::ICON_EMOJI_ID_MASK) != 0;
auto edit_is_closed = (action->flags_ & telegram_api::messageActionTopicEdit::CLOSED_MASK) != 0;
return td::make_unique<MessageTopicEdit>(ForumTopicEditedData{std::move(action->title_),
edit_icon_custom_emoji_id, action->icon_emoji_id_,
edit_is_closed, action->closed_});
auto edit_is_hidden = (action->flags_ & telegram_api::messageActionTopicEdit::HIDDEN_MASK) != 0;
return td::make_unique<MessageTopicEdit>(
ForumTopicEditedData{std::move(action->title_), edit_icon_custom_emoji_id, action->icon_emoji_id_,
edit_is_closed, action->closed_, edit_is_hidden, action->hidden_});
}
default:
UNREACHABLE();
@ -5363,7 +5386,8 @@ tl_object_ptr<td_api::MessageContent> get_message_content_object(const MessageCo
return make_tl_object<td_api::messageScreenshotTaken>();
case MessageContentType::ChatSetTtl: {
const auto *m = static_cast<const MessageChatSetTtl *>(content);
return make_tl_object<td_api::messageChatSetTtl>(m->ttl);
return make_tl_object<td_api::messageChatSetTtl>(
m->ttl, td->contacts_manager_->get_user_id_object(m->from_user_id, "MessageChatSetTtl"));
}
case MessageContentType::Call: {
const auto *m = static_cast<const MessageCall *>(content);
@ -6059,8 +6083,11 @@ void add_message_content_dependencies(Dependencies &dependencies, const MessageC
break;
case MessageContentType::ScreenshotTaken:
break;
case MessageContentType::ChatSetTtl:
case MessageContentType::ChatSetTtl: {
const auto *content = static_cast<const MessageChatSetTtl *>(message_content);
dependencies.add(content->from_user_id);
break;
}
case MessageContentType::Unsupported:
break;
case MessageContentType::Call:

View File

@ -98,7 +98,7 @@ unique_ptr<MessageContent> create_contact_registered_message_content();
unique_ptr<MessageContent> create_screenshot_taken_message_content();
unique_ptr<MessageContent> create_chat_set_ttl_message_content(int32 ttl);
unique_ptr<MessageContent> create_chat_set_ttl_message_content(int32 ttl, UserId from_user_id);
Result<InputMessageContent> get_input_message_content(
DialogId dialog_id, tl_object_ptr<td_api::InputMessageContent> &&input_message_content, Td *td, bool is_premium);

View File

@ -6,6 +6,7 @@
//
#include "td/telegram/MessageId.h"
#include "td/utils/algorithm.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
@ -24,6 +25,46 @@ MessageId::MessageId(ScheduledServerMessageId server_message_id, int32 send_date
SCHEDULED_MASK;
}
MessageId MessageId::get_message_id(const telegram_api::Message *message_ptr, bool is_scheduled) {
CHECK(message_ptr != nullptr)
switch (message_ptr->get_id()) {
case telegram_api::messageEmpty::ID: {
auto message = static_cast<const telegram_api::messageEmpty *>(message_ptr);
return is_scheduled ? MessageId() : MessageId(ServerMessageId(message->id_));
}
case telegram_api::message::ID: {
auto message = static_cast<const telegram_api::message *>(message_ptr);
return is_scheduled ? MessageId(ScheduledServerMessageId(message->id_), message->date_)
: MessageId(ServerMessageId(message->id_));
}
case telegram_api::messageService::ID: {
auto message = static_cast<const telegram_api::messageService *>(message_ptr);
return is_scheduled ? MessageId(ScheduledServerMessageId(message->id_), message->date_)
: MessageId(ServerMessageId(message->id_));
}
default:
UNREACHABLE();
return MessageId();
}
}
MessageId MessageId::get_message_id(const tl_object_ptr<telegram_api::Message> &message_ptr, bool is_scheduled) {
return get_message_id(message_ptr.get(), is_scheduled);
}
vector<MessageId> MessageId::get_message_ids(const vector<int64> &input_message_ids) {
return transform(input_message_ids, [](int64 input_message_id) { return MessageId(input_message_id); });
}
vector<int32> MessageId::get_server_message_ids(const vector<MessageId> &message_ids) {
return transform(message_ids, [](MessageId message_id) { return message_id.get_server_message_id().get(); });
}
vector<int32> MessageId::get_scheduled_server_message_ids(const vector<MessageId> &message_ids) {
return transform(message_ids,
[](MessageId message_id) { return message_id.get_scheduled_server_message_id().get(); });
}
bool MessageId::is_valid() const {
if (id <= 0 || id > max().get()) {
return false;

View File

@ -8,6 +8,7 @@
#include "td/telegram/ScheduledServerMessageId.h"
#include "td/telegram/ServerMessageId.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/common.h"
#include "td/utils/HashTableUtils.h"
@ -73,6 +74,16 @@ class MessageId {
return MessageId(static_cast<int64>(std::numeric_limits<int32>::max()) << SERVER_ID_SHIFT);
}
static MessageId get_message_id(const telegram_api::Message *message_ptr, bool is_scheduled);
static MessageId get_message_id(const tl_object_ptr<telegram_api::Message> &message_ptr, bool is_scheduled);
static vector<MessageId> get_message_ids(const vector<int64> &input_message_ids);
static vector<int32> get_server_message_ids(const vector<MessageId> &message_ids);
static vector<int32> get_scheduled_server_message_ids(const vector<MessageId> &message_ids);
bool is_valid() const;
bool is_valid_scheduled() const;

View File

@ -135,7 +135,7 @@ class GetMessagesReactionsQuery final : public Td::ResultHandler {
CHECK(input_peer != nullptr);
send_query(G()->net_query_creator().create(telegram_api::messages_getMessagesReactions(
std::move(input_peer), MessagesManager::get_server_message_ids(message_ids_))));
std::move(input_peer), MessageId::get_server_message_ids(message_ids_))));
}
void on_result(BufferSlice packet) final {

View File

@ -16,6 +16,10 @@ int32 MessageTtl::get_message_ttl_object() const {
return period_;
}
int32 MessageTtl::get_input_ttl_period() const {
return period_;
}
bool operator==(const MessageTtl &lhs, const MessageTtl &rhs) {
return lhs.period_ == rhs.period_;
}

View File

@ -34,6 +34,8 @@ class MessageTtl {
int32 get_message_ttl_object() const;
int32 get_input_ttl_period() const;
template <class StorerT>
void store(StorerT &storer) const {
td::store(period_, storer);

View File

@ -0,0 +1,73 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
//
// 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)
//
#include "td/telegram/MessagesInfo.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/ForumTopicManager.h"
#include "td/telegram/Td.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
namespace td {
MessagesInfo get_messages_info(Td *td, DialogId dialog_id,
telegram_api::object_ptr<telegram_api::messages_Messages> &&messages_ptr,
const char *source) {
CHECK(messages_ptr != nullptr);
LOG(DEBUG) << "Receive result for " << source << ": " << to_string(messages_ptr);
vector<tl_object_ptr<telegram_api::User>> users;
vector<tl_object_ptr<telegram_api::Chat>> chats;
vector<tl_object_ptr<telegram_api::ForumTopic>> topics;
MessagesInfo result;
switch (messages_ptr->get_id()) {
case telegram_api::messages_messages::ID: {
auto messages = move_tl_object_as<telegram_api::messages_messages>(messages_ptr);
users = std::move(messages->users_);
chats = std::move(messages->chats_);
result.total_count = narrow_cast<int32>(messages->messages_.size());
result.messages = std::move(messages->messages_);
break;
}
case telegram_api::messages_messagesSlice::ID: {
auto messages = move_tl_object_as<telegram_api::messages_messagesSlice>(messages_ptr);
users = std::move(messages->users_);
chats = std::move(messages->chats_);
result.total_count = messages->count_;
result.messages = std::move(messages->messages_);
break;
}
case telegram_api::messages_channelMessages::ID: {
auto messages = move_tl_object_as<telegram_api::messages_channelMessages>(messages_ptr);
users = std::move(messages->users_);
chats = std::move(messages->chats_);
topics = std::move(messages->topics_);
result.total_count = messages->count_;
result.messages = std::move(messages->messages_);
result.is_channel_messages = true;
break;
}
case telegram_api::messages_messagesNotModified::ID:
LOG(ERROR) << "Server returned messagesNotModified in response to " << source;
break;
default:
UNREACHABLE();
break;
}
td->contacts_manager_->on_get_users(std::move(users), source);
td->contacts_manager_->on_get_chats(std::move(chats), source);
td->forum_topic_manager_->on_get_forum_topic_infos(dialog_id, std::move(topics), source);
return result;
}
} // namespace td

View File

@ -0,0 +1,28 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
//
// 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/DialogId.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/common.h"
namespace td {
class Td;
struct MessagesInfo {
vector<telegram_api::object_ptr<telegram_api::Message>> messages;
int32 total_count = 0;
bool is_channel_messages = false;
};
MessagesInfo get_messages_info(Td *td, DialogId dialog_id,
telegram_api::object_ptr<telegram_api::messages_Messages> &&messages_ptr,
const char *source);
} // namespace td

File diff suppressed because it is too large Load Diff

View File

@ -37,6 +37,7 @@
#include "td/telegram/MessageReplyHeader.h"
#include "td/telegram/MessageReplyInfo.h"
#include "td/telegram/MessageSearchFilter.h"
#include "td/telegram/MessagesInfo.h"
#include "td/telegram/MessageThreadInfo.h"
#include "td/telegram/MessageTtl.h"
#include "td/telegram/net/DcId.h"
@ -160,19 +161,6 @@ class MessagesManager final : public Actor {
~MessagesManager() final;
void memory_stats(vector<string> &output);
static vector<MessageId> get_message_ids(const vector<int64> &input_message_ids);
static vector<int32> get_server_message_ids(const vector<MessageId> &message_ids);
static vector<int32> get_scheduled_server_message_ids(const vector<MessageId> &message_ids);
static MessageId get_message_id(const tl_object_ptr<telegram_api::Message> &message_ptr, bool is_scheduled);
static DialogId get_message_dialog_id(const tl_object_ptr<telegram_api::Message> &message_ptr);
static FullMessageId get_full_message_id(const tl_object_ptr<telegram_api::Message> &message_ptr, bool is_scheduled);
tl_object_ptr<telegram_api::InputPeer> get_input_peer(DialogId dialog_id, AccessRights access_rights) const;
static tl_object_ptr<telegram_api::InputPeer> get_input_peer_force(DialogId dialog_id);
@ -193,13 +181,6 @@ class MessagesManager final : public Actor {
void on_get_empty_messages(DialogId dialog_id, const vector<MessageId> &empty_message_ids);
struct MessagesInfo {
vector<tl_object_ptr<telegram_api::Message>> messages;
int32 total_count = 0;
bool is_channel_messages = false;
};
MessagesInfo get_messages_info(tl_object_ptr<telegram_api::messages_Messages> &&messages_ptr, const char *source);
void get_channel_difference_if_needed(DialogId dialog_id, MessagesInfo &&messages_info,
Promise<MessagesInfo> &&promise);
@ -707,12 +688,12 @@ class MessagesManager final : public Actor {
void create_dialog(DialogId dialog_id, bool force, Promise<Unit> &&promise);
DialogId create_new_group_chat(const vector<UserId> &user_ids, const string &title, int64 &random_id,
Promise<Unit> &&promise);
DialogId create_new_group_chat(const vector<UserId> &user_ids, const string &title, MessageTtl message_ttl,
int64 &random_id, Promise<Unit> &&promise);
DialogId create_new_channel_chat(const string &title, bool is_megagroup, const string &description,
const DialogLocation &location, bool for_import, int64 &random_id,
Promise<Unit> &&promise);
const DialogLocation &location, bool for_import, MessageTtl message_ttl,
int64 &random_id, Promise<Unit> &&promise);
void create_new_secret_chat(UserId user_id, Promise<SecretChatId> &&promise);
@ -751,7 +732,7 @@ class MessagesManager final : public Actor {
static tl_object_ptr<td_api::chats> get_chats_object(const std::pair<int32, vector<DialogId>> &dialog_ids);
tl_object_ptr<td_api::chatFilter> get_chat_filter_object(DialogFilterId dialog_filter_id) const;
tl_object_ptr<td_api::chatFilter> get_chat_filter_object(DialogFilterId dialog_filter_id);
tl_object_ptr<td_api::messages> get_dialog_history(DialogId dialog_id, MessageId from_message_id, int32 offset,
int32 limit, int left_tries, bool only_local,
@ -2730,6 +2711,8 @@ class MessagesManager final : public Actor {
bool update_dialog_silent_send_message(Dialog *d, bool silent_send_message);
void set_dialog_message_ttl(Dialog *d, MessageTtl message_ttl);
ChatReactions get_message_available_reactions(const Dialog *d, const Message *m,
bool dissalow_custom_for_non_premium);
@ -2834,7 +2817,7 @@ class MessagesManager final : public Actor {
void update_dialogs_hints(const Dialog *d);
void update_dialogs_hints_rating(const Dialog *d);
td_api::object_ptr<td_api::chatFilter> get_chat_filter_object(const DialogFilter *filter) const;
td_api::object_ptr<td_api::chatFilter> get_chat_filter_object(const DialogFilter *filter);
void load_dialog_filter_dialogs(DialogFilterId dialog_filter_id, vector<InputDialogId> &&input_dialog_ids,
Promise<Unit> &&promise);
@ -2844,6 +2827,8 @@ class MessagesManager final : public Actor {
void load_dialog_filter(const DialogFilter *filter, bool force, Promise<Unit> &&promise);
void delete_dialogs_from_filter(const DialogFilter *dialog_filter, vector<DialogId> &&dialog_ids, const char *source);
void on_get_recommended_dialog_filters(Result<vector<tl_object_ptr<telegram_api::dialogFilterSuggested>>> result,
Promise<td_api::object_ptr<td_api::recommendedChatFilters>> &&promise);
@ -3378,6 +3363,8 @@ class MessagesManager final : public Actor {
bool is_group_dialog(DialogId dialog_id) const;
bool is_forum_channel(DialogId dialog_id) const;
bool is_broadcast_channel(DialogId dialog_id) const;
bool is_deleted_secret_chat(const Dialog *d) const;

View File

@ -17,6 +17,7 @@
#include "td/telegram/files/FileLocation.h"
#include "td/telegram/files/FileManager.h"
#include "td/telegram/files/FileType.h"
#include "td/telegram/ForumTopicManager.h"
#include "td/telegram/Global.h"
#include "td/telegram/logevent/LogEvent.h"
#include "td/telegram/logevent/LogEventHelper.h"
@ -183,11 +184,14 @@ class GetSavedRingtonesQuery final : public Td::ResultHandler {
class GetDialogNotifySettingsQuery final : public Td::ResultHandler {
DialogId dialog_id_;
MessageId top_thread_message_id_;
public:
void send(DialogId dialog_id) {
void send(DialogId dialog_id, MessageId top_thread_message_id) {
dialog_id_ = dialog_id;
auto input_notify_peer = td_->notification_settings_manager_->get_input_notify_peer(dialog_id);
top_thread_message_id_ = top_thread_message_id;
auto input_notify_peer =
td_->notification_settings_manager_->get_input_notify_peer(dialog_id, top_thread_message_id);
CHECK(input_notify_peer != nullptr);
send_query(G()->net_query_creator().create(telegram_api::account_getNotifySettings(std::move(input_notify_peer))));
}
@ -199,15 +203,21 @@ class GetDialogNotifySettingsQuery final : public Td::ResultHandler {
}
auto ptr = result_ptr.move_as_ok();
td_->messages_manager_->on_update_dialog_notify_settings(dialog_id_, std::move(ptr),
"GetDialogNotifySettingsQuery");
td_->notification_settings_manager_->on_get_dialog_notification_settings_query_finished(dialog_id_, Status::OK());
if (top_thread_message_id_.is_valid()) {
td_->forum_topic_manager_->on_update_forum_topic_notify_settings(dialog_id_, top_thread_message_id_,
std::move(ptr), "GetDialogNotifySettingsQuery");
} else {
td_->messages_manager_->on_update_dialog_notify_settings(dialog_id_, std::move(ptr),
"GetDialogNotifySettingsQuery");
}
td_->notification_settings_manager_->on_get_dialog_notification_settings_query_finished(
dialog_id_, top_thread_message_id_, Status::OK());
}
void on_error(Status status) final {
td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetDialogNotifySettingsQuery");
td_->notification_settings_manager_->on_get_dialog_notification_settings_query_finished(dialog_id_,
std::move(status));
td_->notification_settings_manager_->on_get_dialog_notification_settings_query_finished(
dialog_id_, top_thread_message_id_, std::move(status));
}
};
@ -308,15 +318,18 @@ class GetScopeNotifySettingsQuery final : public Td::ResultHandler {
class UpdateDialogNotifySettingsQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
DialogId dialog_id_;
MessageId top_thread_message_id_;
public:
explicit UpdateDialogNotifySettingsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(DialogId dialog_id, const DialogNotificationSettings &new_settings) {
void send(DialogId dialog_id, MessageId top_thread_message_id, const DialogNotificationSettings &new_settings) {
dialog_id_ = dialog_id;
top_thread_message_id_ = top_thread_message_id;
auto input_notify_peer = td_->notification_settings_manager_->get_input_notify_peer(dialog_id);
auto input_notify_peer =
td_->notification_settings_manager_->get_input_notify_peer(dialog_id, top_thread_message_id);
if (input_notify_peer == nullptr) {
return on_error(Status::Error(500, "Can't update chat notification settings"));
}
@ -360,9 +373,10 @@ class UpdateDialogNotifySettingsQuery final : public Td::ResultHandler {
}
if (!td_->auth_manager_->is_bot() &&
td_->notification_settings_manager_->get_input_notify_peer(dialog_id_) != nullptr) {
td_->notification_settings_manager_->get_input_notify_peer(dialog_id_, top_thread_message_id_) != nullptr) {
// trying to repair notification settings for this dialog
td_->notification_settings_manager_->send_get_dialog_notification_settings_query(dialog_id_, Promise<>());
td_->notification_settings_manager_->send_get_dialog_notification_settings_query(
dialog_id_, top_thread_message_id_, Promise<>());
}
promise_.set_error(std::move(status));
@ -596,7 +610,7 @@ bool NotificationSettingsManager::get_scope_disable_mention_notifications(Notifi
}
tl_object_ptr<telegram_api::InputNotifyPeer> NotificationSettingsManager::get_input_notify_peer(
DialogId dialog_id) const {
DialogId dialog_id, MessageId top_thread_message_id) const {
if (!td_->messages_manager_->have_dialog(dialog_id)) {
return nullptr;
}
@ -604,6 +618,11 @@ tl_object_ptr<telegram_api::InputNotifyPeer> NotificationSettingsManager::get_in
if (input_peer == nullptr) {
return nullptr;
}
if (top_thread_message_id.is_valid()) {
CHECK(top_thread_message_id.is_server());
return telegram_api::make_object<telegram_api::inputNotifyForumTopic>(
std::move(input_peer), top_thread_message_id.get_server_message_id().get());
}
return make_tl_object<telegram_api::inputNotifyPeer>(std::move(input_peer));
}
@ -1339,6 +1358,7 @@ FileSourceId NotificationSettingsManager::get_saved_ringtones_file_source_id() {
}
void NotificationSettingsManager::send_get_dialog_notification_settings_query(DialogId dialog_id,
MessageId top_thread_message_id,
Promise<Unit> &&promise) {
if (td_->auth_manager_->is_bot() || dialog_id.get_type() == DialogType::SecretChat) {
LOG(WARNING) << "Can't get notification settings for " << dialog_id;
@ -1349,14 +1369,14 @@ void NotificationSettingsManager::send_get_dialog_notification_settings_query(Di
return promise.set_error(Status::Error(400, "Can't access the chat"));
}
auto &promises = get_dialog_notification_settings_queries_[dialog_id];
auto &promises = get_dialog_notification_settings_queries_[{dialog_id, top_thread_message_id}];
promises.push_back(std::move(promise));
if (promises.size() != 1) {
// query has already been sent, just wait for the result
return;
}
td_->create_handler<GetDialogNotifySettingsQuery>()->send(dialog_id);
td_->create_handler<GetDialogNotifySettingsQuery>()->send(dialog_id, top_thread_message_id);
}
const ScopeNotificationSettings *NotificationSettingsManager::get_scope_notification_settings(
@ -1383,9 +1403,10 @@ void NotificationSettingsManager::send_get_scope_notification_settings_query(Not
}
void NotificationSettingsManager::on_get_dialog_notification_settings_query_finished(DialogId dialog_id,
MessageId top_thread_message_id,
Status &&status) {
CHECK(!td_->auth_manager_->is_bot());
auto it = get_dialog_notification_settings_queries_.find(dialog_id);
auto it = get_dialog_notification_settings_queries_.find({dialog_id, top_thread_message_id});
CHECK(it != get_dialog_notification_settings_queries_.end());
CHECK(!it->second.empty());
auto promises = std::move(it->second);
@ -1398,10 +1419,11 @@ void NotificationSettingsManager::on_get_dialog_notification_settings_query_fini
}
}
void NotificationSettingsManager::update_dialog_notify_settings(DialogId dialog_id,
void NotificationSettingsManager::update_dialog_notify_settings(DialogId dialog_id, MessageId top_thread_message_id,
const DialogNotificationSettings &new_settings,
Promise<Unit> &&promise) {
td_->create_handler<UpdateDialogNotifySettingsQuery>(std::move(promise))->send(dialog_id, new_settings);
td_->create_handler<UpdateDialogNotifySettingsQuery>(std::move(promise))
->send(dialog_id, top_thread_message_id, new_settings);
}
Status NotificationSettingsManager::set_scope_notification_settings(

View File

@ -10,6 +10,8 @@
#include "td/telegram/DialogNotificationSettings.h"
#include "td/telegram/files/FileId.h"
#include "td/telegram/files/FileSourceId.h"
#include "td/telegram/FullMessageId.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/NotificationSettingsScope.h"
#include "td/telegram/ScopeNotificationSettings.h"
#include "td/telegram/td_api.h"
@ -52,7 +54,8 @@ class NotificationSettingsManager final : public Actor {
bool get_scope_disable_mention_notifications(NotificationSettingsScope scope) const;
tl_object_ptr<telegram_api::InputNotifyPeer> get_input_notify_peer(DialogId dialog_id) const;
tl_object_ptr<telegram_api::InputNotifyPeer> get_input_notify_peer(DialogId dialog_id,
MessageId top_thread_message_id) const;
void on_update_scope_notify_settings(NotificationSettingsScope scope,
tl_object_ptr<telegram_api::peerNotifySettings> &&peer_notify_settings);
@ -75,16 +78,18 @@ class NotificationSettingsManager final : public Actor {
void send_save_ringtone_query(FileId ringtone_file_id, bool unsave,
Promise<telegram_api::object_ptr<telegram_api::account_SavedRingtone>> &&promise);
void send_get_dialog_notification_settings_query(DialogId dialog_id, Promise<Unit> &&promise);
void send_get_dialog_notification_settings_query(DialogId dialog_id, MessageId top_thread_message_id,
Promise<Unit> &&promise);
const ScopeNotificationSettings *get_scope_notification_settings(NotificationSettingsScope scope,
Promise<Unit> &&promise);
void send_get_scope_notification_settings_query(NotificationSettingsScope scope, Promise<Unit> &&promise);
void on_get_dialog_notification_settings_query_finished(DialogId dialog_id, Status &&status);
void on_get_dialog_notification_settings_query_finished(DialogId dialog_id, MessageId top_thread_message_id,
Status &&status);
void update_dialog_notify_settings(DialogId dialog_id, const DialogNotificationSettings &new_settings,
Promise<Unit> &&promise);
void update_dialog_notify_settings(DialogId dialog_id, MessageId top_thread_message_id,
const DialogNotificationSettings &new_settings, Promise<Unit> &&promise);
Status set_scope_notification_settings(NotificationSettingsScope scope,
td_api::object_ptr<td_api::scopeNotificationSettings> &&notification_settings)
@ -211,7 +216,7 @@ class NotificationSettingsManager final : public Actor {
vector<Promise<Unit>> reload_saved_ringtones_queries_;
vector<Promise<Unit>> repair_saved_ringtones_queries_;
FlatHashMap<DialogId, vector<Promise<Unit>>, DialogIdHash> get_dialog_notification_settings_queries_;
FlatHashMap<FullMessageId, vector<Promise<Unit>>, FullMessageIdHash> get_dialog_notification_settings_queries_;
};
} // namespace td

View File

@ -117,7 +117,10 @@ OptionManager::OptionManager(Td *td)
set_option_integer("themed_emoji_statuses_sticker_set_id", sticker_set_id);
}
if (!have_option("forum_member_count_min")) {
set_option_integer("forum_member_count_min", 200);
set_option_integer("forum_member_count_min", G()->is_test_dc() ? 3 : 100);
}
if (!have_option("aggressive_anti_spam_supergroup_member_count_min")) {
set_option_integer("aggressive_anti_spam_supergroup_member_count_min", G()->is_test_dc() ? 1 : 100);
}
}
@ -261,6 +264,8 @@ bool OptionManager::is_internal_option(Slice name) {
name == "dice_emojis" || name == "dice_success_values";
case 'e':
return name == "edit_time_limit" || name == "emoji_sounds";
case 'f':
return name == "fragment_prefixes";
case 'i':
return name == "ignored_restriction_reasons";
case 'l':
@ -355,6 +360,9 @@ void OptionManager::on_option_updated(Slice name) {
if (name == "favorite_stickers_limit") {
td_->stickers_manager_->on_update_favorite_stickers_limit();
}
if (name == "fragment_prefixes") {
send_closure(td_->contacts_manager_actor_, &ContactsManager::on_update_fragment_prefixes);
}
break;
case 'i':
if (name == "ignored_restriction_reasons") {
@ -513,7 +521,7 @@ td_api::object_ptr<td_api::OptionValue> OptionManager::get_option_synchronously(
break;
case 'v':
if (name == "version") {
return td_api::make_object<td_api::optionValueString>("1.8.8");
return td_api::make_object<td_api::optionValueString>("1.8.9");
}
break;
}

View File

@ -1224,7 +1224,10 @@ void PollManager::on_stop_poll_finished(PollId poll_id, FullMessageId full_messa
}
if (td_->auth_manager_->is_bot()) {
td_->messages_manager_->on_external_update_message_content(full_message_id);
if ((server_poll_messages_.count(poll_id) > 0 && server_poll_messages_[poll_id].count(full_message_id) > 0) ||
(other_poll_messages_.count(poll_id) > 0 && other_poll_messages_[poll_id].count(full_message_id) > 0)) {
td_->messages_manager_->on_external_update_message_content(full_message_id);
}
}
promise.set_result(std::move(result));

View File

@ -120,6 +120,8 @@ SendCodeHelper::AuthenticationCodeInfo SendCodeHelper::get_authentication_code_i
return {AuthenticationCodeInfo::Type::FlashCall, 0, string()};
case telegram_api::auth_codeTypeMissedCall::ID:
return {AuthenticationCodeInfo::Type::MissedCall, 0, string()};
case telegram_api::auth_codeTypeFragmentSms::ID:
return {AuthenticationCodeInfo::Type::Fragment, 0, string()};
default:
UNREACHABLE();
return AuthenticationCodeInfo();
@ -151,6 +153,11 @@ SendCodeHelper::AuthenticationCodeInfo SendCodeHelper::get_sent_authentication_c
return AuthenticationCodeInfo{AuthenticationCodeInfo::Type::MissedCall, code_type->length_,
std::move(code_type->prefix_)};
}
case telegram_api::auth_sentCodeTypeFragmentSms::ID: {
auto code_type = move_tl_object_as<telegram_api::auth_sentCodeTypeFragmentSms>(sent_code_type_ptr);
return AuthenticationCodeInfo{AuthenticationCodeInfo::Type::Fragment, code_type->length_,
std::move(code_type->url_)};
}
case telegram_api::auth_sentCodeTypeEmailCode::ID:
case telegram_api::auth_sentCodeTypeSetUpEmailRequired::ID:
default:
@ -175,6 +182,9 @@ td_api::object_ptr<td_api::AuthenticationCodeType> SendCodeHelper::get_authentic
case AuthenticationCodeInfo::Type::MissedCall:
return td_api::make_object<td_api::authenticationCodeTypeMissedCall>(authentication_code_info.pattern,
authentication_code_info.length);
case AuthenticationCodeInfo::Type::Fragment:
return td_api::make_object<td_api::authenticationCodeTypeFragment>(authentication_code_info.pattern,
authentication_code_info.length);
default:
UNREACHABLE();
return nullptr;

View File

@ -61,7 +61,7 @@ class SendCodeHelper {
static constexpr int32 SENT_CODE_FLAG_HAS_TIMEOUT = 1 << 2;
struct AuthenticationCodeInfo {
enum class Type : int32 { None, Message, Sms, Call, FlashCall, MissedCall };
enum class Type : int32 { None, Message, Sms, Call, FlashCall, MissedCall, Fragment };
Type type = Type::None;
int32 length = 0;
string pattern;

View File

@ -74,6 +74,7 @@
#include "td/telegram/MessageSender.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/MessageThreadInfo.h"
#include "td/telegram/MessageTtl.h"
#include "td/telegram/misc.h"
#include "td/telegram/net/ConnectionCreator.h"
#include "td/telegram/net/DcId.h"
@ -1060,7 +1061,7 @@ class GetMessagesRequest final : public RequestOnceActor {
GetMessagesRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, const vector<int64> &message_ids)
: RequestOnceActor(std::move(td), request_id)
, dialog_id_(dialog_id)
, message_ids_(MessagesManager::get_message_ids(message_ids)) {
, message_ids_(MessageId::get_message_ids(message_ids)) {
}
};
@ -1629,12 +1630,14 @@ class CreateChatRequest final : public RequestActor<> {
class CreateNewGroupChatRequest final : public RequestActor<> {
vector<UserId> user_ids_;
string title_;
MessageTtl message_ttl_;
int64 random_id_;
DialogId dialog_id_;
void do_run(Promise<Unit> &&promise) final {
dialog_id_ = td_->messages_manager_->create_new_group_chat(user_ids_, title_, random_id_, std::move(promise));
dialog_id_ =
td_->messages_manager_->create_new_group_chat(user_ids_, title_, message_ttl_, random_id_, std::move(promise));
}
void do_send_result() final {
@ -1643,10 +1646,12 @@ class CreateNewGroupChatRequest final : public RequestActor<> {
}
public:
CreateNewGroupChatRequest(ActorShared<Td> td, uint64 request_id, vector<UserId> user_ids, string title)
CreateNewGroupChatRequest(ActorShared<Td> td, uint64 request_id, vector<UserId> user_ids, string title,
int32 message_ttl)
: RequestActor(std::move(td), request_id)
, user_ids_(std::move(user_ids))
, title_(std::move(title))
, message_ttl_(message_ttl)
, random_id_(0) {
}
};
@ -1692,13 +1697,14 @@ class CreateNewSupergroupChatRequest final : public RequestActor<> {
string description_;
DialogLocation location_;
bool for_import_;
MessageTtl message_ttl_;
int64 random_id_;
DialogId dialog_id_;
void do_run(Promise<Unit> &&promise) final {
dialog_id_ = td_->messages_manager_->create_new_channel_chat(title_, is_megagroup_, description_, location_,
for_import_, random_id_, std::move(promise));
dialog_id_ = td_->messages_manager_->create_new_channel_chat(
title_, is_megagroup_, description_, location_, for_import_, message_ttl_, random_id_, std::move(promise));
}
void do_send_result() final {
@ -1709,13 +1715,14 @@ class CreateNewSupergroupChatRequest final : public RequestActor<> {
public:
CreateNewSupergroupChatRequest(ActorShared<Td> td, uint64 request_id, string title, bool is_megagroup,
string description, td_api::object_ptr<td_api::chatLocation> &&location,
bool for_import)
bool for_import, int32 message_ttl)
: RequestActor(std::move(td), request_id)
, title_(std::move(title))
, is_megagroup_(is_megagroup)
, description_(std::move(description))
, location_(std::move(location))
, for_import_(for_import)
, message_ttl_(message_ttl)
, random_id_(0) {
}
};
@ -4481,6 +4488,28 @@ void Td::on_request(uint64 id, td_api::setUserPrivacySettingRules &request) {
std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getDefaultMessageTtl &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result<int32> result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
promise.set_value(td_api::make_object<td_api::messageTtl>(result.ok()));
}
});
get_default_message_ttl(this, std::move(query_promise));
}
void Td::on_request(uint64 id, const td_api::setDefaultMessageTtl &request) {
CHECK_IS_USER();
if (request.ttl_ == nullptr) {
return send_error_raw(id, 400, "New default message TTL must be non-empty");
}
CREATE_OK_REQUEST_PROMISE();
set_default_message_ttl(this, request.ttl_->ttl_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getAccountTtl &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
@ -4527,6 +4556,19 @@ void Td::on_request(uint64 id, td_api::resendChangePhoneNumberCode &request) {
send_closure(change_phone_number_manager_, &PhoneNumberManager::resend_authentication_code, id);
}
void Td::on_request(uint64 id, const td_api::getUserLink &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
contacts_manager_->get_user_link(std::move(promise));
}
void Td::on_request(uint64 id, td_api::searchUserByToken &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.token_);
CREATE_REQUEST_PROMISE();
contacts_manager_->search_user_by_token(std::move(request.token_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getActiveSessions &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
@ -5061,9 +5103,9 @@ void Td::on_request(uint64 id, const td_api::closeChat &request) {
void Td::on_request(uint64 id, const td_api::viewMessages &request) {
CHECK_IS_USER();
answer_ok_query(id, messages_manager_->view_messages(
DialogId(request.chat_id_), MessageId(request.message_thread_id_),
MessagesManager::get_message_ids(request.message_ids_), request.force_read_));
answer_ok_query(
id, messages_manager_->view_messages(DialogId(request.chat_id_), MessageId(request.message_thread_id_),
MessageId::get_message_ids(request.message_ids_), request.force_read_));
}
void Td::on_request(uint64 id, const td_api::openMessageContent &request) {
@ -5326,7 +5368,7 @@ void Td::on_request(uint64 id, const td_api::removeNotificationGroup &request) {
void Td::on_request(uint64 id, const td_api::deleteMessages &request) {
CREATE_OK_REQUEST_PROMISE();
messages_manager_->delete_messages(DialogId(request.chat_id_), MessagesManager::get_message_ids(request.message_ids_),
messages_manager_->delete_messages(DialogId(request.chat_id_), MessageId::get_message_ids(request.message_ids_),
request.revoke_, std::move(promise));
}
@ -5554,7 +5596,36 @@ void Td::on_request(uint64 id, td_api::editForumTopic &request) {
CLEAN_INPUT_STRING(request.name_);
CREATE_OK_REQUEST_PROMISE();
forum_topic_manager_->edit_forum_topic(DialogId(request.chat_id_), MessageId(request.message_thread_id_),
std::move(request.name_), CustomEmojiId(request.icon_custom_emoji_id_),
std::move(request.name_), request.edit_icon_custom_emoji_,
CustomEmojiId(request.icon_custom_emoji_id_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getForumTopic &request) {
CREATE_REQUEST_PROMISE();
forum_topic_manager_->get_forum_topic(DialogId(request.chat_id_), MessageId(request.message_thread_id_),
std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getForumTopicLink &request) {
CREATE_REQUEST_PROMISE();
auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result<string> result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
promise.set_value(td_api::make_object<td_api::httpUrl>(result.move_as_ok()));
}
});
forum_topic_manager_->get_forum_topic_link(DialogId(request.chat_id_), MessageId(request.message_thread_id_),
std::move(query_promise));
}
void Td::on_request(uint64 id, td_api::getForumTopics &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.query_);
CREATE_REQUEST_PROMISE();
forum_topic_manager_->get_forum_topics(DialogId(request.chat_id_), std::move(request.query_), request.offset_date_,
MessageId(request.offset_message_id_),
MessageId(request.offset_message_thread_id_), request.limit_,
std::move(promise));
}
@ -5564,6 +5635,12 @@ void Td::on_request(uint64 id, const td_api::toggleForumTopicIsClosed &request)
request.is_closed_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::toggleGeneralForumTopicIsHidden &request) {
CREATE_OK_REQUEST_PROMISE();
forum_topic_manager_->toggle_forum_topic_is_hidden(DialogId(request.chat_id_), request.is_hidden_,
std::move(promise));
}
void Td::on_request(uint64 id, const td_api::deleteForumTopic &request) {
CREATE_OK_REQUEST_PROMISE();
forum_topic_manager_->delete_forum_topic(DialogId(request.chat_id_), MessageId(request.message_thread_id_),
@ -5617,7 +5694,7 @@ void Td::on_request(uint64 id, td_api::sendChatScreenshotTakenNotification &requ
}
void Td::on_request(uint64 id, td_api::forwardMessages &request) {
auto input_message_ids = MessagesManager::get_message_ids(request.message_ids_);
auto input_message_ids = MessageId::get_message_ids(request.message_ids_);
auto message_copy_options =
transform(input_message_ids, [send_copy = request.send_copy_, remove_caption = request.remove_caption_](
MessageId) { return MessageCopyOptions(send_copy, remove_caption); });
@ -5634,8 +5711,7 @@ void Td::on_request(uint64 id, td_api::forwardMessages &request) {
void Td::on_request(uint64 id, const td_api::resendMessages &request) {
DialogId dialog_id(request.chat_id_);
auto r_message_ids =
messages_manager_->resend_messages(dialog_id, MessagesManager::get_message_ids(request.message_ids_));
auto r_message_ids = messages_manager_->resend_messages(dialog_id, MessageId::get_message_ids(request.message_ids_));
if (r_message_ids.is_error()) {
return send_closure(actor_id(this), &Td::send_error, id, r_message_ids.move_as_error());
}
@ -5674,7 +5750,8 @@ void Td::on_request(uint64 id, td_api::createSecretChat &request) {
void Td::on_request(uint64 id, td_api::createNewBasicGroupChat &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.title_);
CREATE_REQUEST(CreateNewGroupChatRequest, UserId::get_user_ids(request.user_ids_), std::move(request.title_));
CREATE_REQUEST(CreateNewGroupChatRequest, UserId::get_user_ids(request.user_ids_), std::move(request.title_),
request.message_ttl_);
}
void Td::on_request(uint64 id, td_api::createNewSupergroupChat &request) {
@ -5682,8 +5759,10 @@ void Td::on_request(uint64 id, td_api::createNewSupergroupChat &request) {
CLEAN_INPUT_STRING(request.title_);
CLEAN_INPUT_STRING(request.description_);
CREATE_REQUEST(CreateNewSupergroupChatRequest, std::move(request.title_), !request.is_channel_,
std::move(request.description_), std::move(request.location_), request.for_import_);
std::move(request.description_), std::move(request.location_), request.for_import_,
request.message_ttl_);
}
void Td::on_request(uint64 id, td_api::createNewSecretChat &request) {
CREATE_REQUEST(CreateNewSecretChatRequest, request.user_id_);
}
@ -7000,6 +7079,13 @@ void Td::on_request(uint64 id, const td_api::toggleSupergroupIsAllHistoryAvailab
request.is_all_history_available_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::toggleSupergroupIsAggressiveAntiSpamEnabled &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
contacts_manager_->toggle_channel_is_aggressive_anti_spam_enabled(
ChannelId(request.supergroup_id_), request.is_aggressive_anti_spam_enabled_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::toggleSupergroupIsForum &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
@ -7016,7 +7102,14 @@ void Td::on_request(uint64 id, const td_api::reportSupergroupSpam &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
contacts_manager_->report_channel_spam(ChannelId(request.supergroup_id_),
MessagesManager::get_message_ids(request.message_ids_), std::move(promise));
MessageId::get_message_ids(request.message_ids_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::reportSupergroupAntiSpamFalsePositive &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
contacts_manager_->report_channel_anti_spam_false_positive(ChannelId(request.supergroup_id_),
MessageId(request.message_id_), std::move(promise));
}
void Td::on_request(uint64 id, td_api::getSupergroupMembers &request) {
@ -7328,7 +7421,7 @@ void Td::on_request(uint64 id, td_api::reportChat &request) {
return send_error_raw(id, r_report_reason.error().code(), r_report_reason.error().message());
}
CREATE_OK_REQUEST_PROMISE();
messages_manager_->report_dialog(DialogId(request.chat_id_), MessagesManager::get_message_ids(request.message_ids_),
messages_manager_->report_dialog(DialogId(request.chat_id_), MessageId::get_message_ids(request.message_ids_),
r_report_reason.move_as_ok(), std::move(promise));
}
@ -7378,6 +7471,13 @@ void Td::on_request(uint64 id, td_api::setChatNotificationSettings &request) {
std::move(request.notification_settings_)));
}
void Td::on_request(uint64 id, td_api::setForumTopicNotificationSettings &request) {
CHECK_IS_USER();
answer_ok_query(id, forum_topic_manager_->set_forum_topic_notification_settings(
DialogId(request.chat_id_), MessageId(request.message_thread_id_),
std::move(request.notification_settings_)));
}
void Td::on_request(uint64 id, td_api::setScopeNotificationSettings &request) {
CHECK_IS_USER();
if (request.scope_ == nullptr) {

View File

@ -479,6 +479,10 @@ class Td final : public Actor {
void on_request(uint64 id, td_api::setUserPrivacySettingRules &request);
void on_request(uint64 id, const td_api::getDefaultMessageTtl &request);
void on_request(uint64 id, const td_api::setDefaultMessageTtl &request);
void on_request(uint64 id, const td_api::getAccountTtl &request);
void on_request(uint64 id, const td_api::setAccountTtl &request);
@ -491,6 +495,10 @@ class Td final : public Actor {
void on_request(uint64 id, td_api::resendChangePhoneNumberCode &request);
void on_request(uint64 id, const td_api::getUserLink &request);
void on_request(uint64 id, td_api::searchUserByToken &request);
void on_request(uint64 id, const td_api::getActiveSessions &request);
void on_request(uint64 id, const td_api::terminateSession &request);
@ -751,8 +759,16 @@ class Td final : public Actor {
void on_request(uint64 id, td_api::editForumTopic &request);
void on_request(uint64 id, const td_api::getForumTopic &request);
void on_request(uint64 id, const td_api::getForumTopicLink &request);
void on_request(uint64 id, td_api::getForumTopics &request);
void on_request(uint64 id, const td_api::toggleForumTopicIsClosed &request);
void on_request(uint64 id, const td_api::toggleGeneralForumTopicIsHidden &request);
void on_request(uint64 id, const td_api::deleteForumTopic &request);
void on_request(uint64 id, td_api::setGameScore &request);
@ -1113,12 +1129,16 @@ class Td final : public Actor {
void on_request(uint64 id, const td_api::toggleSupergroupIsAllHistoryAvailable &request);
void on_request(uint64 id, const td_api::toggleSupergroupIsAggressiveAntiSpamEnabled &request);
void on_request(uint64 id, const td_api::toggleSupergroupIsForum &request);
void on_request(uint64 id, const td_api::toggleSupergroupIsBroadcastGroup &request);
void on_request(uint64 id, const td_api::reportSupergroupSpam &request);
void on_request(uint64 id, const td_api::reportSupergroupAntiSpamFalsePositive &request);
void on_request(uint64 id, td_api::getSupergroupMembers &request);
void on_request(uint64 id, td_api::closeSecretChat &request);
@ -1211,6 +1231,8 @@ class Td final : public Actor {
void on_request(uint64 id, td_api::setChatNotificationSettings &request);
void on_request(uint64 id, td_api::setForumTopicNotificationSettings &request);
void on_request(uint64 id, td_api::setScopeNotificationSettings &request);
void on_request(uint64 id, const td_api::resetAllNotificationSettings &request);

View File

@ -22,6 +22,7 @@
#include "td/telegram/DownloadManager.h"
#include "td/telegram/EmojiStatus.h"
#include "td/telegram/FolderId.h"
#include "td/telegram/ForumTopicManager.h"
#include "td/telegram/Global.h"
#include "td/telegram/GroupCallManager.h"
#include "td/telegram/InlineQueriesManager.h"
@ -768,7 +769,6 @@ bool UpdatesManager::is_acceptable_message(const telegram_api::Message *message_
case telegram_api::messageActionContactSignUp::ID:
case telegram_api::messageActionGroupCall::ID:
case telegram_api::messageActionGroupCallScheduled::ID:
case telegram_api::messageActionSetMessagesTTL::ID:
case telegram_api::messageActionSetChatTheme::ID:
case telegram_api::messageActionChatJoinedByRequest::ID:
case telegram_api::messageActionWebViewDataSentMe::ID:
@ -838,6 +838,14 @@ bool UpdatesManager::is_acceptable_message(const telegram_api::Message *message_
}
break;
}
case telegram_api::messageActionSetMessagesTTL::ID: {
auto set_messages_ttl = static_cast<const telegram_api::messageActionSetMessagesTTL *>(action);
if (set_messages_ttl->auto_setting_from_ != 0 &&
!is_acceptable_user(UserId(set_messages_ttl->auto_setting_from_))) {
return false;
}
break;
}
default:
UNREACHABLE();
return false;
@ -1139,11 +1147,26 @@ FlatHashSet<int64> UpdatesManager::get_sent_messages_random_ids(const telegram_a
FlatHashSet<int64> random_ids;
auto updates = get_updates(updates_ptr);
if (updates != nullptr) {
auto new_messages = get_new_messages(updates_ptr);
for (auto &update : *updates) {
if (update->get_id() == telegram_api::updateMessageID::ID) {
int64 random_id = static_cast<const telegram_api::updateMessageID *>(update.get())->random_id_;
if (random_id != 0 && !random_ids.insert(random_id).second) {
LOG(ERROR) << "Receive twice updateMessageID for " << random_id;
auto update_message_id = static_cast<const telegram_api::updateMessageID *>(update.get());
int64 random_id = update_message_id->random_id_;
if (random_id != 0) {
bool found_message = false;
for (auto message : new_messages) {
MessageId message_id = MessageId::get_message_id(message.first, message.second);
if (message.second) {
found_message |= message_id.is_valid_scheduled() &&
message_id.get_scheduled_server_message_id().get() == update_message_id->id_;
} else {
found_message |=
message_id.is_valid() && message_id.get_server_message_id().get() == update_message_id->id_;
}
}
if (found_message && !random_ids.insert(random_id).second) {
LOG(ERROR) << "Receive twice updateMessageID for " << random_id;
}
}
}
}
@ -1184,7 +1207,7 @@ const telegram_api::Message *UpdatesManager::get_message_by_random_id(const tele
} else if (constructor_id == telegram_api::updateNewChannelMessage::ID) {
message = &static_cast<const telegram_api::updateNewChannelMessage *>(update.get())->message_;
}
if (message != nullptr && MessagesManager::get_full_message_id(*message, false) == full_message_id) {
if (message != nullptr && FullMessageId::get_full_message_id(*message, false) == full_message_id) {
if (result != nullptr) {
return nullptr;
}
@ -1194,19 +1217,34 @@ const telegram_api::Message *UpdatesManager::get_message_by_random_id(const tele
return result;
}
vector<const tl_object_ptr<telegram_api::Message> *> UpdatesManager::get_new_messages(
bool UpdatesManager::is_additional_service_message(const telegram_api::Message *message) {
if (message->get_id() != telegram_api::messageService::ID) {
return false;
}
auto action_id = static_cast<const telegram_api::messageService *>(message)->action_->get_id();
return action_id == telegram_api::messageActionSetMessagesTTL::ID;
}
vector<std::pair<const telegram_api::Message *, bool>> UpdatesManager::get_new_messages(
const telegram_api::Updates *updates_ptr) {
vector<const tl_object_ptr<telegram_api::Message> *> messages;
vector<std::pair<const telegram_api::Message *, bool>> messages;
auto updates = get_updates(updates_ptr);
if (updates != nullptr) {
for (auto &update : *updates) {
const telegram_api::Message *message = nullptr;
bool is_scheduled = false;
auto constructor_id = update->get_id();
if (constructor_id == telegram_api::updateNewMessage::ID) {
messages.emplace_back(&static_cast<const telegram_api::updateNewMessage *>(update.get())->message_);
message = static_cast<const telegram_api::updateNewMessage *>(update.get())->message_.get();
} else if (constructor_id == telegram_api::updateNewChannelMessage::ID) {
messages.emplace_back(&static_cast<const telegram_api::updateNewChannelMessage *>(update.get())->message_);
message = static_cast<const telegram_api::updateNewChannelMessage *>(update.get())->message_.get();
} else if (constructor_id == telegram_api::updateNewScheduledMessage::ID) {
messages.emplace_back(&static_cast<const telegram_api::updateNewScheduledMessage *>(update.get())->message_);
message = static_cast<const telegram_api::updateNewScheduledMessage *>(update.get())->message_.get();
is_scheduled = true;
}
if (message != nullptr && !is_additional_service_message(message)) {
messages.emplace_back(message, is_scheduled);
}
}
}
@ -1344,21 +1382,21 @@ int32 UpdatesManager::get_update_edit_message_pts(const telegram_api::Updates *u
switch (update_ptr->get_id()) {
case telegram_api::updateEditMessage::ID: {
auto update = static_cast<const telegram_api::updateEditMessage *>(update_ptr.get());
if (MessagesManager::get_full_message_id(update->message_, false) == full_message_id) {
if (FullMessageId::get_full_message_id(update->message_, false) == full_message_id) {
return update->pts_;
}
return 0;
}
case telegram_api::updateEditChannelMessage::ID: {
auto update = static_cast<const telegram_api::updateEditChannelMessage *>(update_ptr.get());
if (MessagesManager::get_full_message_id(update->message_, false) == full_message_id) {
if (FullMessageId::get_full_message_id(update->message_, false) == full_message_id) {
return update->pts_;
}
return 0;
}
case telegram_api::updateNewScheduledMessage::ID: {
auto update = static_cast<const telegram_api::updateNewScheduledMessage *>(update_ptr.get());
auto new_full_message_id = MessagesManager::get_full_message_id(update->message_, true);
auto new_full_message_id = FullMessageId::get_full_message_id(update->message_, true);
if (new_full_message_id.get_dialog_id() == full_message_id.get_dialog_id()) {
auto new_message_id = new_full_message_id.get_message_id();
auto old_message_id = full_message_id.get_message_id();
@ -1689,9 +1727,8 @@ void UpdatesManager::after_get_difference() {
VLOG(get_difference) << "Finished to apply " << total_update_count << " postponed updates";
auto passed_time = Time::now() - begin_time;
if (passed_time >= UPDATE_APPLY_WARNING_TIME) {
LOG(WARNING) << "Applied " << total_update_count << " postponed for "
<< (Time::now() - get_difference_start_time_) << " updates in " << chunk_count << " chunks in "
<< passed_time;
LOG(WARNING) << "Applied " << total_update_count << " updates in " << chunk_count << " chunks in " << passed_time
<< " seconds after postponing them for " << (Time::now() - get_difference_start_time_) << " seconds";
}
}
@ -1714,8 +1751,8 @@ void UpdatesManager::after_get_difference() {
<< postponed_pts_updates_.size() << " pending pts updates";
auto passed_time = Time::now() - begin_time;
if (passed_time >= UPDATE_APPLY_WARNING_TIME) {
LOG(WARNING) << "Applied " << update_count << " postponed for " << (Time::now() - get_difference_start_time_)
<< " pts updates in " << passed_time;
LOG(WARNING) << "Applied " << update_count << " pts updates in " << passed_time
<< " seconds after postponing them for " << (Time::now() - get_difference_start_time_) << " seconds";
}
}
@ -1891,7 +1928,7 @@ void UpdatesManager::on_pending_updates(vector<tl_object_ptr<telegram_api::Updat
// for channels we can try to replace unacceptable update with updateChannelTooLong
if (message_ptr != nullptr) {
auto dialog_id = td_->messages_manager_->get_message_dialog_id(*message_ptr);
auto dialog_id = DialogId::get_message_dialog_id(*message_ptr);
if (dialog_id.get_type() == DialogType::Channel) {
auto channel_id = dialog_id.get_channel_id();
if (td_->contacts_manager_->have_channel_force(channel_id)) {
@ -2563,6 +2600,11 @@ void UpdatesManager::process_postponed_pts_updates() {
continue;
}
if (Time::now() - begin_time >= td::min(UPDATE_APPLY_WARNING_TIME / 2, 0.1)) {
// the updates will be applied or skipped later; reget the remaining updates through getDifference
break;
}
auto last_update_it = update_it;
for (int32 i = 1; true; i++) {
++last_update_it;
@ -2616,7 +2658,7 @@ void UpdatesManager::process_postponed_pts_updates() {
LOG(WARNING) << "PTS has changed from " << initial_pts << " to " << old_pts << " after skipping "
<< skipped_update_count << ", applying " << applied_update_count << " and keeping "
<< postponed_pts_updates_.size() << " postponed for " << (Time::now() - get_difference_start_time_)
<< " updates in " << passed_time;
<< " seconds updates in " << passed_time << " seconds";
}
}
@ -2671,7 +2713,7 @@ void UpdatesManager::process_pending_pts_updates() {
if (passed_time >= UPDATE_APPLY_WARNING_TIME) {
LOG(WARNING) << "PTS has changed from " << initial_pts << " to " << get_pts() << " after applying "
<< applied_update_count << " and keeping " << pending_pts_updates_.size() << " pending updates in "
<< passed_time;
<< passed_time << " seconds";
}
}
@ -2728,7 +2770,7 @@ void UpdatesManager::process_pending_seq_updates() {
if (passed_time >= UPDATE_APPLY_WARNING_TIME) {
LOG(WARNING) << "Seq has changed from " << initial_seq << " to " << seq_ << " after applying "
<< applied_update_count << " and keeping " << pending_seq_updates_.size() << " pending updates in "
<< passed_time;
<< passed_time << " seconds";
}
}
@ -2782,7 +2824,7 @@ void UpdatesManager::process_pending_qts_updates() {
if (passed_time >= UPDATE_APPLY_WARNING_TIME) {
LOG(WARNING) << "QTS has changed from " << initial_qts << " to " << get_qts() << " after applying "
<< applied_update_count << " and keeping " << pending_qts_updates_.size() << " pending updates in "
<< passed_time;
<< passed_time << " seconds";
}
}
@ -2825,7 +2867,7 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateNewMessage> upd
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateNewChannelMessage> update, Promise<Unit> &&promise) {
DialogId dialog_id = MessagesManager::get_message_dialog_id(update->message_);
DialogId dialog_id = DialogId::get_message_dialog_id(update->message_);
int new_pts = update->pts_;
int pts_count = update->pts_count_;
td_->messages_manager_->add_pending_channel_update(dialog_id, std::move(update), new_pts, pts_count,
@ -2914,7 +2956,7 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannel> update
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateEditChannelMessage> update, Promise<Unit> &&promise) {
DialogId dialog_id = MessagesManager::get_message_dialog_id(update->message_);
DialogId dialog_id = DialogId::get_message_dialog_id(update->message_);
int new_pts = update->pts_;
int pts_count = update->pts_count_;
td_->messages_manager_->add_pending_channel_update(dialog_id, std::move(update), new_pts, pts_count,
@ -3012,7 +3054,8 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updatePinnedChannelMe
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateNotifySettings> update, Promise<Unit> &&promise) {
switch (update->peer_->get_id()) {
case telegram_api::notifyPeer::ID: {
DialogId dialog_id(static_cast<const telegram_api::notifyPeer *>(update->peer_.get())->peer_);
auto notify_peer = static_cast<const telegram_api::notifyPeer *>(update->peer_.get());
DialogId dialog_id(notify_peer->peer_);
if (dialog_id.is_valid()) {
td_->messages_manager_->on_update_dialog_notify_settings(dialog_id, std::move(update->notify_settings_),
"updateNotifySettings");
@ -3033,9 +3076,18 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateNotifySettings>
td_->notification_settings_manager_->on_update_scope_notify_settings(NotificationSettingsScope::Channel,
std::move(update->notify_settings_));
break;
case telegram_api::notifyForumTopic::ID:
// TODO
case telegram_api::notifyForumTopic::ID: {
auto notify_peer = static_cast<const telegram_api::notifyForumTopic *>(update->peer_.get());
DialogId dialog_id(notify_peer->peer_);
auto top_thread_message_id = MessageId(ServerMessageId(notify_peer->top_msg_id_));
if (dialog_id.is_valid() && top_thread_message_id.is_valid()) {
td_->forum_topic_manager_->on_update_forum_topic_notify_settings(
dialog_id, top_thread_message_id, std::move(update->notify_settings_), "updateNotifySettings");
} else {
LOG(ERROR) << "Receive wrong " << to_string(update);
}
break;
}
default:
UNREACHABLE();
}
@ -3153,7 +3205,7 @@ bool UpdatesManager::check_pts_update(const tl_object_ptr<telegram_api::Update>
return true;
case telegram_api::updateNewMessage::ID: {
auto update_new_message = static_cast<const telegram_api::updateNewMessage *>(update.get());
return check_pts_update_dialog_id(MessagesManager::get_message_dialog_id(update_new_message->message_));
return check_pts_update_dialog_id(DialogId::get_message_dialog_id(update_new_message->message_));
}
case telegram_api::updateReadHistoryInbox::ID: {
auto update_read_history_inbox = static_cast<const telegram_api::updateReadHistoryInbox *>(update.get());
@ -3165,7 +3217,7 @@ bool UpdatesManager::check_pts_update(const tl_object_ptr<telegram_api::Update>
}
case telegram_api::updateEditMessage::ID: {
auto update_edit_message = static_cast<const telegram_api::updateEditMessage *>(update.get());
return check_pts_update_dialog_id(MessagesManager::get_message_dialog_id(update_edit_message->message_));
return check_pts_update_dialog_id(DialogId::get_message_dialog_id(update_edit_message->message_));
}
case telegram_api::updatePinnedMessages::ID: {
auto update_pinned_messages = static_cast<const telegram_api::updatePinnedMessages *>(update.get());
@ -3756,4 +3808,8 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannelPinnedTo
promise.set_value(Unit());
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannelPinnedTopics> update, Promise<Unit> &&promise) {
promise.set_value(Unit());
}
} // namespace td

View File

@ -31,6 +31,7 @@
#include <functional>
#include <map>
#include <utility>
namespace td {
@ -107,7 +108,8 @@ class UpdatesManager final : public Actor {
static const telegram_api::Message *get_message_by_random_id(const telegram_api::Updates *updates_ptr,
DialogId dialog_id, int64 random_id);
static vector<const tl_object_ptr<telegram_api::Message> *> get_new_messages(
// [Message, is_scheduled]
static vector<std::pair<const telegram_api::Message *, bool>> get_new_messages(
const telegram_api::Updates *updates_ptr);
static vector<InputGroupCallId> get_update_new_group_call_ids(const telegram_api::Updates *updates_ptr);
@ -379,6 +381,8 @@ class UpdatesManager final : public Actor {
static bool is_channel_pts_update(const telegram_api::Update *update);
static bool is_additional_service_message(const telegram_api::Message *message);
static const vector<tl_object_ptr<telegram_api::Update>> *get_updates(const telegram_api::Updates *updates_ptr);
static vector<tl_object_ptr<telegram_api::Update>> *get_updates(telegram_api::Updates *updates_ptr);
@ -562,6 +566,8 @@ class UpdatesManager final : public Actor {
// unsupported updates
void on_update(tl_object_ptr<telegram_api::updateChannelPinnedTopic> update, Promise<Unit> &&promise);
void on_update(tl_object_ptr<telegram_api::updateChannelPinnedTopics> update, Promise<Unit> &&promise);
};
} // namespace td

View File

@ -10,7 +10,7 @@
namespace td {
constexpr int32 MTPROTO_LAYER = 148;
constexpr int32 MTPROTO_LAYER = 150;
enum class Version : int32 {
Initial, // 0
@ -57,6 +57,7 @@ enum class Version : int32 {
AddStickerSetListFlags,
AddInputInvoiceFlags,
AddVideoNoteFlags,
AddMessageChatSetTtlFlags,
Next
};

View File

@ -2172,6 +2172,10 @@ class CliClient final : public Actor {
} else {
send_request(td_api::make_object<td_api::searchContacts>("", as_limit(args)));
}
} else if (op == "gul") {
send_request(td_api::make_object<td_api::getUserLink>());
} else if (op == "subt") {
send_request(td_api::make_object<td_api::searchUserByToken>(args));
} else if (op == "AddContact") {
UserId user_id;
string first_name;
@ -2519,6 +2523,12 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::setOption>(name, td_api::make_object<td_api::optionValueString>(value)));
} else if (op == "me") {
send_request(td_api::make_object<td_api::getMe>());
} else if (op == "sdmttl") {
int32 ttl;
get_args(args, ttl);
send_request(td_api::make_object<td_api::setDefaultMessageTtl>(td_api::make_object<td_api::messageTtl>(ttl)));
} else if (op == "gdmttl") {
send_request(td_api::make_object<td_api::getDefaultMessageTtl>());
} else if (op == "sattl") {
int32 days;
get_args(args, days);
@ -3870,15 +3880,42 @@ class CliClient final : public Actor {
ChatId chat_id;
MessageThreadId message_thread_id;
string name;
bool edit_icon_custom_emoji;
int64 icon_custom_emoji_id;
get_args(args, chat_id, message_thread_id, name, icon_custom_emoji_id);
send_request(td_api::make_object<td_api::editForumTopic>(chat_id, message_thread_id, name, icon_custom_emoji_id));
get_args(args, chat_id, message_thread_id, name, edit_icon_custom_emoji, icon_custom_emoji_id);
send_request(td_api::make_object<td_api::editForumTopic>(chat_id, message_thread_id, name, edit_icon_custom_emoji,
icon_custom_emoji_id));
} else if (op == "gft") {
ChatId chat_id;
MessageThreadId message_thread_id;
get_args(args, chat_id, message_thread_id);
send_request(td_api::make_object<td_api::getForumTopic>(chat_id, message_thread_id));
} else if (op == "gftl") {
ChatId chat_id;
MessageThreadId message_thread_id;
get_args(args, chat_id, message_thread_id);
send_request(td_api::make_object<td_api::getForumTopicLink>(chat_id, message_thread_id));
} else if (op == "gfts") {
ChatId chat_id;
string query;
int32 offset_date;
MessageId offset_message_id;
MessageThreadId offset_message_thread_id;
string limit;
get_args(args, chat_id, query, offset_date, offset_message_id, offset_message_thread_id, limit);
send_request(td_api::make_object<td_api::getForumTopics>(chat_id, query, offset_date, offset_message_id,
offset_message_thread_id, as_limit(limit)));
} else if (op == "tftic") {
ChatId chat_id;
MessageThreadId message_thread_id;
bool is_closed;
get_args(args, chat_id, message_thread_id, is_closed);
send_request(td_api::make_object<td_api::toggleForumTopicIsClosed>(chat_id, message_thread_id, is_closed));
} else if (op == "tgftih") {
ChatId chat_id;
bool is_hidden;
get_args(args, chat_id, is_hidden);
send_request(td_api::make_object<td_api::toggleGeneralForumTopicIsHidden>(chat_id, is_hidden));
} else if (op == "dft") {
ChatId chat_id;
MessageThreadId message_thread_id;
@ -4261,18 +4298,22 @@ class CliClient final : public Actor {
} else if (op == "cnbgc") {
string user_ids_string;
string title;
get_args(args, user_ids_string, title);
send_request(td_api::make_object<td_api::createNewBasicGroupChat>(as_user_ids(user_ids_string), title));
} else if (op == "cnchc") {
send_request(td_api::make_object<td_api::createNewSupergroupChat>(args, true, "Description", nullptr, false));
} else if (op == "cnsgc") {
send_request(td_api::make_object<td_api::createNewSupergroupChat>(args, false, "Description", nullptr, false));
int32 message_ttl;
get_args(args, user_ids_string, title, message_ttl);
send_request(
td_api::make_object<td_api::createNewBasicGroupChat>(as_user_ids(user_ids_string), title, message_ttl));
} else if (op == "cnchc" || op == "cnchcttl") {
send_request(td_api::make_object<td_api::createNewSupergroupChat>(args, true, "Description", nullptr,
op == "cnchcttl" ? 86400 : 0, false));
} else if (op == "cnsgc" || op == "cnsgcttl") {
send_request(td_api::make_object<td_api::createNewSupergroupChat>(args, false, "Description", nullptr,
op == "cnsgcttl" ? 86400 : 0, false));
} else if (op == "cnsgcloc") {
send_request(td_api::make_object<td_api::createNewSupergroupChat>(
args, false, "Description",
td_api::make_object<td_api::chatLocation>(as_location("40.0", "60.0", ""), "address"), false));
td_api::make_object<td_api::chatLocation>(as_location("40.0", "60.0", ""), "address"), 0, false));
} else if (op == "cnsgcimport") {
send_request(td_api::make_object<td_api::createNewSupergroupChat>(args, false, "Description", nullptr, true));
send_request(td_api::make_object<td_api::createNewSupergroupChat>(args, false, "Description", nullptr, 0, true));
} else if (op == "UpgradeBasicGroupChatToSupergroupChat") {
ChatId chat_id;
get_args(args, chat_id);
@ -4625,6 +4666,12 @@ class CliClient final : public Actor {
get_args(args, supergroup_id, is_all_history_available);
send_request(td_api::make_object<td_api::toggleSupergroupIsAllHistoryAvailable>(as_supergroup_id(supergroup_id),
is_all_history_available));
} else if (op == "tsgas") {
string supergroup_id;
bool is_aggressive_anti_spam_enabled;
get_args(args, supergroup_id, is_aggressive_anti_spam_enabled);
send_request(td_api::make_object<td_api::toggleSupergroupIsAggressiveAntiSpamEnabled>(
as_supergroup_id(supergroup_id), is_aggressive_anti_spam_enabled));
} else if (op == "tsgif") {
string supergroup_id;
bool is_forum;
@ -4846,29 +4893,37 @@ class CliClient final : public Actor {
as_notification_settings_scope(args), op == "gcnses"));
} else if (op == "gsns") {
send_request(td_api::make_object<td_api::getScopeNotificationSettings>(as_notification_settings_scope(args)));
} else if (op == "scns" || op == "ssns") {
string chat_id_or_scope;
} else if (op == "scns" || op == "ssns" || op == "sftns") {
string scope;
string mute_for;
int64 sound_id;
string show_preview;
string disable_pinned_message_notifications;
string disable_mention_notifications;
get_args(args, chat_id_or_scope, mute_for, sound_id, show_preview, disable_pinned_message_notifications,
get_args(args, scope, mute_for, sound_id, show_preview, disable_pinned_message_notifications,
disable_mention_notifications);
if (op == "scns") {
send_request(td_api::make_object<td_api::setChatNotificationSettings>(
as_chat_id(chat_id_or_scope),
td_api::make_object<td_api::chatNotificationSettings>(
mute_for.empty(), to_integer<int32>(mute_for), sound_id == -1, sound_id, show_preview.empty(),
as_bool(show_preview), disable_pinned_message_notifications.empty(),
as_bool(disable_pinned_message_notifications), disable_mention_notifications.empty(),
as_bool(disable_mention_notifications))));
} else {
if (op == "ssns") {
send_request(td_api::make_object<td_api::setScopeNotificationSettings>(
as_notification_settings_scope(chat_id_or_scope),
as_notification_settings_scope(scope),
td_api::make_object<td_api::scopeNotificationSettings>(
to_integer<int32>(mute_for), sound_id, as_bool(show_preview),
as_bool(disable_pinned_message_notifications), as_bool(disable_mention_notifications))));
} else {
auto settings = td_api::make_object<td_api::chatNotificationSettings>(
mute_for.empty(), to_integer<int32>(mute_for), sound_id == -1, sound_id, show_preview.empty(),
as_bool(show_preview), disable_pinned_message_notifications.empty(),
as_bool(disable_pinned_message_notifications), disable_mention_notifications.empty(),
as_bool(disable_mention_notifications));
if (op == "scns") {
send_request(
td_api::make_object<td_api::setChatNotificationSettings>(as_chat_id(scope), std::move(settings)));
} else {
string chat_id;
string message_id;
std::tie(chat_id, message_id) = split(scope, ',');
send_request(td_api::make_object<td_api::setForumTopicNotificationSettings>(
as_chat_id(chat_id), as_message_id(message_id), std::move(settings)));
}
}
} else if (op == "rans") {
send_request(td_api::make_object<td_api::resetAllNotificationSettings>());
@ -4963,6 +5018,12 @@ class CliClient final : public Actor {
get_args(args, supergroup_id, message_ids);
send_request(td_api::make_object<td_api::reportSupergroupSpam>(as_supergroup_id(supergroup_id),
as_message_ids(message_ids)));
} else if (op == "rsgasfp") {
string supergroup_id;
MessageId message_id;
get_args(args, supergroup_id, message_id);
send_request(td_api::make_object<td_api::reportSupergroupAntiSpamFalsePositive>(as_supergroup_id(supergroup_id),
message_id));
} else if (op == "gdiff") {
send_request(td_api::make_object<td_api::testGetDifference>());
} else if (op == "dproxy") {

View File

@ -95,8 +95,7 @@ void FileGcWorker::run_gc(const FileGcParameters &parameters, std::vector<FullFi
double now = Clocks::system();
// Keep all immune files
// Remove all files with (atime > now - max_time_from_last_access)
// Remove all suitable files with (atime > now - max_time_from_last_access)
td::remove_if(files, [&](const FullFileInfo &info) {
if (token_) {
return false;

View File

@ -84,7 +84,7 @@ Result<size_t> HttpReader::read_next(HttpQuery *query, bool can_be_slow) {
return Status::Error(501, "Unimplemented: unsupported transfer-encoding");
}
if (content_encoding_.empty()) {
if (content_encoding_.empty() || content_encoding_ == "none") {
} else if (content_encoding_ == "gzip" || content_encoding_ == "deflate") {
gzip_flow_ = GzipByteFlow(Gzip::Mode::Decode);
GzipByteFlow::Options options;
@ -174,8 +174,8 @@ Result<size_t> HttpReader::read_next(HttpQuery *query, bool can_be_slow) {
}
// save content to a file
if (temp_file_.empty()) {
auto file = open_temp_file("file");
if (file.is_error()) {
auto open_status = open_temp_file("file");
if (open_status.is_error()) {
return Status::Error(500, "Internal Server Error: can't create temporary file");
}
}
@ -408,10 +408,6 @@ Result<bool> HttpReader::parse_multipart_form_data(bool can_be_slow) {
if (query_->files_.size() == max_files_) {
return Status::Error(413, "Request Entity Too Large: too many files attached");
}
auto file = open_temp_file(file_name_);
if (file.is_error()) {
return Status::Error(500, "Internal Server Error: can't create temporary file");
}
// don't need to save headers for files
file_field_name_ = field_name_.str();
@ -467,6 +463,12 @@ Result<bool> HttpReader::parse_multipart_form_data(bool can_be_slow) {
if (!can_be_slow) {
return Status::Error("SLOW");
}
if (temp_file_.empty()) {
auto open_status = open_temp_file(file_name_);
if (open_status.is_error()) {
return Status::Error(500, "Internal Server Error: can't create temporary file");
}
}
if (find_boundary(content_->clone(), boundary_, form_data_read_length_)) {
auto file_part = content_->cut_head(form_data_read_length_).move_as_buffer_slice();
content_->advance(boundary_.size());

View File

@ -49,7 +49,12 @@ Status AsyncFileLog::init(string path, int64 rotate_threshold, bool redirect_std
if (!Stderr().empty() && redirect_stderr) {
fd.get_native_fd().duplicate(Stderr().get_native_fd()).ignore();
}
size = 0;
auto r_size = fd.get_size();
if (r_fd.is_error()) {
process_fatal_error(PSLICE() << "Failed to get log size: " << r_fd.error() << " in " << __FILE__ << " at "
<< __LINE__ << '\n');
}
size = r_size.move_as_ok();
};
auto append = [&](CSlice slice) {
if (size > rotate_threshold) {

View File

@ -128,7 +128,12 @@ void FileLog::do_after_rotation() {
if (!Stderr().empty() && redirect_stderr_) {
fd_.get_native_fd().duplicate(Stderr().get_native_fd()).ignore();
}
size_ = 0;
auto r_size = fd_.get_size();
if (r_fd.is_error()) {
process_fatal_error(PSLICE() << "Failed to get log size: " << r_fd.error() << " in " << __FILE__ << " at "
<< __LINE__ << '\n');
}
size_ = r_size.move_as_ok();
}
Result<unique_ptr<LogInterface>> FileLog::create(string path, int64 rotate_threshold, bool redirect_stderr) {

View File

@ -12,7 +12,7 @@
#include "td/utils/common.h"
#include "td/utils/invoke.h"
#if TD_WINDOWS
#if TD_WINDOWS && TD_MSVC
#include "td/utils/port/detail/NativeFd.h"
#endif
#include "td/utils/port/detail/ThreadIdGuard.h"
@ -25,7 +25,7 @@
#include <type_traits>
#include <utility>
#if TD_WINDOWS
#if TD_WINDOWS && TD_MSVC
#define TD_HAVE_THREAD_AFFINITY 1
#endif
@ -73,14 +73,16 @@ class ThreadStl {
return std::thread::hardware_concurrency();
}
#if TD_WINDOWS
#if TD_WINDOWS && TD_MSVC
using id = DWORD;
#else
using id = std::thread::id;
#endif
id get_id() noexcept {
#if TD_WINDOWS
#if TD_WINDOWS && TD_MSVC
static_assert(std::is_same<decltype(thread_.native_handle()), HANDLE>::value,
"Expected HANDLE as native thread type");
return GetThreadId(thread_.native_handle());
#else
return thread_.get_id();
@ -136,7 +138,7 @@ class ThreadStl {
};
namespace this_thread_stl {
#if TD_WINDOWS
#if TD_WINDOWS && TD_MSVC
inline ThreadStl::id get_id() {
return GetCurrentThreadId();
}

View File

@ -34,7 +34,7 @@ static void test_gzencode(const td::string &s) {
auto r = td::gzencode(s, td::max(2, static_cast<int>(100 / s.size())));
ASSERT_TRUE(!r.empty());
LOG(INFO) << "Encoded string of size " << s.size() << " in " << (td::Time::now() - begin_time)
<< " with compression ratio " << static_cast<double>(r.size()) / static_cast<double>(s.size());
<< " seconds with compression ratio " << static_cast<double>(r.size()) / static_cast<double>(s.size());
}
TEST(Gzip, gzencode) {

View File

@ -232,6 +232,9 @@ TEST(Link, parse_internal_link) {
auto user_phone_number = [](const td::string &phone_number) {
return td::td_api::make_object<td::td_api::internalLinkTypeUserPhoneNumber>(phone_number);
};
auto user_token = [](const td::string &token) {
return td::td_api::make_object<td::td_api::internalLinkTypeUserToken>(token);
};
auto video_chat = [](const td::string &chat_username, const td::string &invite_hash, bool is_live_stream) {
return td::td_api::make_object<td::td_api::internalLinkTypeVideoChat>(chat_username, invite_hash, is_live_stream);
};
@ -318,6 +321,20 @@ TEST(Link, parse_internal_link) {
parse_internal_link("tg:resolve?phone=+123", unknown_deep_link("tg://resolve?phone=+123"));
parse_internal_link("tg:resolve?phone=123456 ", unknown_deep_link("tg://resolve?phone=123456 "));
parse_internal_link("tg:contact?token=1", user_token("1"));
parse_internal_link("tg:contact?token=123456", user_token("123456"));
parse_internal_link("tg:contact?token=123456&startattach", user_token("123456"));
parse_internal_link("tg:contact?token=123456&startattach=123", user_token("123456"));
parse_internal_link("tg:contact?token=123456&attach=", user_token("123456"));
parse_internal_link("tg:contact?token=123456&attach=&startattach", user_token("123456"));
parse_internal_link("tg:contact?token=123456&attach=&startattach=123", user_token("123456"));
parse_internal_link("tg:contact?token=01234567890123456789012345678912",
user_token("01234567890123456789012345678912"));
parse_internal_link("tg:contact?token=012345678901234567890123456789123",
user_token("012345678901234567890123456789123"));
parse_internal_link("tg:contact?token=", unknown_deep_link("tg://contact?token="));
parse_internal_link("tg:contact?token=+123", user_token(" 123"));
parse_internal_link("t.me/username/12345?single", message("tg:resolve?domain=username&post=12345&single"));
parse_internal_link("t.me/username/12345?asdasd", message("tg:resolve?domain=username&post=12345"));
parse_internal_link("t.me/username/12345", message("tg:resolve?domain=username&post=12345"));
@ -573,6 +590,12 @@ TEST(Link, parse_internal_link) {
parse_internal_link("t.me/+123456?attach=bot&startattach=1",
attachment_menu_bot(nullptr, user_phone_number("123456"), "bot", "1"));
parse_internal_link("t.me/contact/startattach/adasd", user_token("startattach"));
parse_internal_link("t.me/contact/startattach", user_token("startattach"));
parse_internal_link("t.me/contact/startattach=1", user_token("startattach=1"));
parse_internal_link("t.me/contact/", nullptr);
parse_internal_link("t.me/contact/?attach=&startattach", nullptr);
parse_internal_link("tg:join?invite=abcdef", chat_invite("abcdef"));
parse_internal_link("tg:join?invite=abc%20def", chat_invite("abc%20def"));
parse_internal_link("tg://join?invite=abc%30def", chat_invite("abc0def"));