Merge remote-tracking branch 'td/master'

This commit is contained in:
Andrea Cavalli 2021-12-07 22:05:52 +01:00
commit bcc6636f3a
42 changed files with 2303 additions and 737 deletions

View File

@ -6,7 +6,7 @@ if (POLICY CMP0065)
cmake_policy(SET CMP0065 NEW) cmake_policy(SET CMP0065 NEW)
endif() endif()
project(TDLib VERSION 1.7.9 LANGUAGES CXX C) project(TDLib VERSION 1.7.10 LANGUAGES CXX C)
if (NOT DEFINED CMAKE_MODULE_PATH) if (NOT DEFINED CMAKE_MODULE_PATH)
set(CMAKE_MODULE_PATH "") set(CMAKE_MODULE_PATH "")

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: Or you could install `TDLib` and then reference it in your CMakeLists.txt like this:
``` ```
find_package(Td 1.7.9 REQUIRED) find_package(Td 1.7.10 REQUIRED)
target_link_libraries(YourTarget PRIVATE Td::TdStatic) target_link_libraries(YourTarget PRIVATE Td::TdStatic)
``` ```
See [example/cpp/CMakeLists.txt](https://github.com/tdlight-team/tdlight/tree/master/example/cpp/CMakeLists.txt). See [example/cpp/CMakeLists.txt](https://github.com/tdlight-team/tdlight/tree/master/example/cpp/CMakeLists.txt).

View File

@ -54,13 +54,13 @@ class MessagesDbBench final : public td::Benchmark {
for (int j = 0; j < 20; j++) { for (int j = 0; j < 20; j++) {
auto message_id = td::MessageId{td::ServerMessageId{message_id_raw + j}}; auto message_id = td::MessageId{td::ServerMessageId{message_id_raw + j}};
auto unique_message_id = td::ServerMessageId{i + 1}; auto unique_message_id = td::ServerMessageId{i + 1};
auto sender_user_id = td::UserId(static_cast<td::int64>(td::Random::fast(1, 1000))); auto sender_dialog_id = td::DialogId(td::UserId(static_cast<td::int64>(td::Random::fast(1, 1000))));
auto random_id = i + 1; auto random_id = i + 1;
auto ttl_expires_at = 0; auto ttl_expires_at = 0;
auto data = td::BufferSlice(td::Random::fast(100, 299)); auto data = td::BufferSlice(td::Random::fast(100, 299));
// use async on same thread. // use async on same thread.
messages_db_async_->add_message({dialog_id, message_id}, unique_message_id, sender_user_id, random_id, messages_db_async_->add_message({dialog_id, message_id}, unique_message_id, sender_dialog_id, random_id,
ttl_expires_at, 0, 0, "", td::NotificationId(), td::MessageId(), ttl_expires_at, 0, 0, "", td::NotificationId(), td::MessageId(),
std::move(data), td::Promise<>()); std::move(data), td::Promise<>());
} }

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.4 FATAL_ERROR)
project(TdExample VERSION 1.0 LANGUAGES CXX) project(TdExample VERSION 1.0 LANGUAGES CXX)
find_package(Td 1.7.9 REQUIRED) find_package(Td 1.7.10 REQUIRED)
add_executable(tdjson_example tdjson_example.cpp) add_executable(tdjson_example tdjson_example.cpp)
target_link_libraries(tdjson_example PRIVATE Td::TdJson) 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"> <PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011">
<Metadata> <Metadata>
<Identity Id="Telegram.Td.UWP" Version="1.7.9" Language="en-US" Publisher="Telegram LLC" /> <Identity Id="Telegram.Td.UWP" Version="1.7.10" Language="en-US" Publisher="Telegram LLC" />
<DisplayName>TDLib for Universal Windows Platform</DisplayName> <DisplayName>TDLib for Universal Windows Platform</DisplayName>
<Description>TDLib is a library for building Telegram clients</Description> <Description>TDLib is a library for building Telegram clients</Description>
<MoreInfo>https://core.telegram.org/tdlib</MoreInfo> <MoreInfo>https://core.telegram.org/tdlib</MoreInfo>

View File

@ -52,9 +52,12 @@ authenticationCodeTypeSms length:int32 = AuthenticationCodeType;
//@description An authentication code is delivered via a phone call to the specified phone number @length Length of the code //@description An authentication code is delivered via a phone call to the specified phone number @length Length of the code
authenticationCodeTypeCall length:int32 = AuthenticationCodeType; authenticationCodeTypeCall length:int32 = AuthenticationCodeType;
//@description An authentication code is delivered by an immediately canceled call to the specified phone number. The number from which the call was made is the code @pattern Pattern of the phone number from which the call will be made //@description An authentication code is delivered by an immediately canceled call to the specified phone number. The phone number from which the call was made is the code that should be entered automatically @pattern Pattern of the phone number from which the call will be made
authenticationCodeTypeFlashCall pattern:string = AuthenticationCodeType; authenticationCodeTypeFlashCall pattern:string = AuthenticationCodeType;
//@description An authentication code is delivered by an immediately canceled call to the specified phone number. The phone number from which the call was made is the code that should 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 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 //@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; authenticationCodeInfo phone_number:string type:AuthenticationCodeType next_type:AuthenticationCodeType timeout:int32 = AuthenticationCodeInfo;
@ -234,10 +237,6 @@ maskPointChin = MaskPoint;
maskPosition point:MaskPoint x_shift:double y_shift:double scale:double = MaskPosition; maskPosition point:MaskPoint x_shift:double y_shift:double scale:double = MaskPosition;
//@description Describes a color replacement for animated emoji @old_color Original animated emoji color in the RGB24 format @new_color Replacement animated emoji color in the RGB24 format
colorReplacement old_color:int32 new_color:int32 = ColorReplacement;
//@description Represents a closed vector path. The path begins at the end point of the last command @commands List of vector path commands //@description Represents a closed vector path. The path begins at the end point of the last command @commands List of vector path commands
closedVectorPath commands:vector<VectorPathCommand> = ClosedVectorPath; closedVectorPath commands:vector<VectorPathCommand> = ClosedVectorPath;
@ -300,9 +299,9 @@ voiceNote duration:int32 waveform:bytes mime_type:string voice:file = VoiceNote;
//@description Describes an animated representation of an emoji //@description Describes an animated representation of an emoji
//@sticker Animated sticker for the emoji //@sticker Animated sticker for the emoji
//@color_replacements List of colors to be replaced while the sticker is rendered //@fitzpatrick_type Emoji modifier fitzpatrick type; 0-6; 0 if none
//@sound File containing the sound to be played when the animated emoji is clicked if any; may be null. The sound is encoded with the Opus codec, and stored inside an OGG container //@sound File containing the sound to be played when the animated emoji is clicked if any; may be null. The sound is encoded with the Opus codec, and stored inside an OGG container
animatedEmoji sticker:sticker color_replacements:vector<colorReplacement> sound:file = AnimatedEmoji; animatedEmoji sticker:sticker fitzpatrick_type:int32 sound:file = AnimatedEmoji;
//@description Describes a user contact @phone_number Phone number of the user @first_name First name of the user; 1-255 characters in length @last_name Last name of the user @vcard Additional data about the user in a form of vCard; 0-2048 bytes in length @user_id Identifier of the user, if known; otherwise 0 //@description Describes a user contact @phone_number Phone number of the user @first_name First name of the user; 1-255 characters in length @last_name Last name of the user @vcard Additional data about the user in a form of vCard; 0-2048 bytes in length @user_id Identifier of the user, if known; otherwise 0
contact phone_number:string first_name:string last_name:string vcard:string user_id:int53 = Contact; contact phone_number:string first_name:string last_name:string vcard:string user_id:int53 = Contact;
@ -322,7 +321,7 @@ game id:int64 short_name:string title:string text:formattedText description:stri
//@description Describes a poll @id Unique poll identifier @question Poll question; 1-300 characters @options List of poll answer options //@description Describes a poll @id Unique poll identifier @question Poll question; 1-300 characters @options List of poll answer options
//@total_voter_count Total number of voters, participating in the poll @recent_voter_user_ids User identifiers of recent voters, if the poll is non-anonymous //@total_voter_count Total number of voters, participating in the poll @recent_voter_user_ids User identifiers of recent voters, if the poll is non-anonymous
//@is_anonymous True, if the poll is anonymous @type Type of the poll //@is_anonymous True, if the poll is anonymous @type Type of the poll
//@open_period Amount of time the poll will be active after creation, in seconds @close_date Point in time (Unix timestamp) when the poll will be automatically closed @is_closed True, if the poll is closed //@open_period Amount of time the poll will be active after creation, in seconds @close_date Point in time (Unix timestamp) when the poll will automatically be closed @is_closed True, if the poll is closed
poll id:int64 question:string options:vector<pollOption> total_voter_count:int32 recent_voter_user_ids:vector<int53> is_anonymous:Bool type:PollType open_period:int32 close_date:int32 is_closed:Bool = Poll; poll id:int64 question:string options:vector<pollOption> total_voter_count:int32 recent_voter_user_ids:vector<int53> is_anonymous:Bool type:PollType open_period:int32 close_date:int32 is_closed:Bool = Poll;
@ -442,13 +441,14 @@ user id:int53 first_name:string last_name:string username:string phone_number:st
//@can_be_called True, if the user can be called //@can_be_called True, if the user can be called
//@supports_video_calls True, if a video call can be created with the user //@supports_video_calls True, if a video call can be created with the user
//@has_private_calls True, if the user can't be called due to their privacy settings //@has_private_calls True, if the user can't be called due to their privacy settings
//@has_private_forwards True, if the user can't be linked in forwarded messages due to their privacy settings
//@need_phone_number_privacy_exception True, if the current user needs to explicitly allow to share their phone number with the user when the method addContact is used //@need_phone_number_privacy_exception True, if the current user needs to explicitly allow to share their phone number with the user when the method addContact is used
//@bio A short user bio //@bio A short user bio
//@share_text For bots, the text that is shown on the bot's profile page and is sent together with the link when users share the bot //@share_text For bots, the text that is shown on the bot's profile page and is sent together with the link when users share the bot
//@param_description For bots, the text shown in the chat with the bot if the chat is empty //@param_description For bots, the text shown in the chat with the bot if the chat is empty
//@group_in_common_count Number of group chats where both the other user and the current user are a member; 0 for the current user //@group_in_common_count Number of group chats where both the other user and the current user are a member; 0 for the current user
//@commands For bots, list of the bot commands //@commands For bots, list of the bot commands
userFullInfo photo:chatPhoto is_blocked:Bool can_be_called:Bool supports_video_calls:Bool has_private_calls:Bool need_phone_number_privacy_exception:Bool bio:string share_text:string description:string group_in_common_count:int32 commands:vector<botCommand> = UserFullInfo; userFullInfo photo:chatPhoto is_blocked:Bool can_be_called:Bool supports_video_calls:Bool has_private_calls:Bool has_private_forwards:Bool need_phone_number_privacy_exception:Bool bio:string share_text:string description:string group_in_common_count:int32 commands:vector<botCommand> = UserFullInfo;
//@description Represents a list of users @total_count Approximate total count of users found @user_ids A list of user identifiers //@description Represents a list of users @total_count Approximate total count of users found @user_ids A list of user identifiers
users total_count:int32 user_ids:vector<int53> = Users; users total_count:int32 user_ids:vector<int53> = Users;
@ -762,11 +762,11 @@ messageForwardInfo origin:MessageForwardOrigin date:int32 public_service_announc
//@description Contains information about replies to a message //@description Contains information about replies to a message
//@reply_count Number of times the message was directly or indirectly replied //@reply_count Number of times the message was directly or indirectly replied
//@recent_repliers Recent repliers to the message; available in channels with a discussion supergroup //@recent_replier_ids Identifiers of recent repliers to the message; available in channels with a discussion supergroup
//@last_read_inbox_message_id Identifier of the last read incoming reply to the message //@last_read_inbox_message_id Identifier of the last read incoming reply to the message
//@last_read_outbox_message_id Identifier of the last read outgoing reply to the message //@last_read_outbox_message_id Identifier of the last read outgoing reply to the message
//@last_message_id Identifier of the last reply to the message //@last_message_id Identifier of the last reply to the message
messageReplyInfo reply_count:int32 recent_repliers:vector<MessageSender> last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 last_message_id:int53 = MessageReplyInfo; messageReplyInfo reply_count:int32 recent_replier_ids:vector<MessageSender> last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 last_message_id:int53 = MessageReplyInfo;
//@description Contains information about interactions with a message //@description Contains information about interactions with a message
//@view_count Number of times the message was viewed //@view_count Number of times the message was viewed
@ -781,13 +781,15 @@ messageInteractionInfo view_count:int32 forward_count:int32 reply_info:messageRe
messageSendingStatePending = MessageSendingState; messageSendingStatePending = MessageSendingState;
//@description The message failed to be sent @error_code An error code; 0 if unknown @error_message Error message //@description The message failed to be sent @error_code An error code; 0 if unknown @error_message Error message
//@can_retry True, if the message can be re-sent @retry_after Time left before the message can be re-sent, in seconds. No update is sent when this field changes //@can_retry True, if the message can be re-sent
messageSendingStateFailed error_code:int32 error_message:string can_retry:Bool retry_after:double = MessageSendingState; //@need_another_sender True, if the message can be re-sent only on behalf of a different sender
//@retry_after Time left before the message can be re-sent, in seconds. No update is sent when this field changes
messageSendingStateFailed error_code:int32 error_message:string can_retry:Bool need_another_sender:Bool retry_after:double = MessageSendingState;
//@description Describes a message //@description Describes a message
//@id Message identifier; unique for the chat to which the message belongs //@id Message identifier; unique for the chat to which the message belongs
//@sender The sender of the message //@sender_id Identifier of the sender of the message
//@chat_id Chat identifier //@chat_id Chat identifier
//@sending_state The sending state of the message; may be null //@sending_state The sending state of the message; may be null
//@scheduling_state The scheduling state of the message; may be null //@scheduling_state The scheduling state of the message; may be null
@ -795,6 +797,7 @@ messageSendingStateFailed error_code:int32 error_message:string can_retry:Bool r
//@is_pinned True, if the message is pinned //@is_pinned True, if the message is pinned
//@can_be_edited True, if the message can be edited. For live location and poll messages this fields shows whether editMessageLiveLocation or stopPoll can be used with this message by the application //@can_be_edited True, if the message can be edited. For live location and poll messages this fields shows whether editMessageLiveLocation or stopPoll can be used with this message by the application
//@can_be_forwarded True, if the message can be forwarded //@can_be_forwarded True, if the message can be forwarded
//@can_be_saved True, if content of the message can be saved locally or copied
//@can_be_deleted_only_for_self True, if the message can be deleted only for the current user while other users will continue to see it //@can_be_deleted_only_for_self True, if the message can be deleted only for the current user while other users will continue to see it
//@can_be_deleted_for_all_users True, if the message can be deleted for all users //@can_be_deleted_for_all_users True, if the message can be deleted for all users
//@can_get_statistics True, if the message statistics are available //@can_get_statistics True, if the message statistics are available
@ -819,7 +822,7 @@ messageSendingStateFailed error_code:int32 error_message:string can_retry:Bool r
//@restriction_reason If non-empty, contains a human-readable description of the reason why access to this message must be restricted //@restriction_reason If non-empty, contains a human-readable description of the reason why access to this message must be restricted
//@content Content of the message //@content Content of the message
//@reply_markup Reply markup for the message; may be null //@reply_markup Reply markup for the message; may be null
message id:int53 sender:MessageSender chat_id:int53 sending_state:MessageSendingState scheduling_state:MessageSchedulingState is_outgoing:Bool is_pinned:Bool can_be_edited:Bool can_be_forwarded:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_get_statistics:Bool can_get_message_thread:Bool can_get_viewers:Bool can_get_media_timestamp_links:Bool has_timestamped_media:Bool is_channel_post:Bool contains_unread_mention:Bool date:int32 edit_date:int32 forward_info:messageForwardInfo interaction_info:messageInteractionInfo reply_in_chat_id:int53 reply_to_message_id:int53 message_thread_id:int53 ttl:int32 ttl_expires_in:double via_bot_user_id:int53 author_signature:string media_album_id:int64 restriction_reason:string content:MessageContent reply_markup:ReplyMarkup = Message; message id:int53 sender_id:MessageSender chat_id:int53 sending_state:MessageSendingState scheduling_state:MessageSchedulingState is_outgoing:Bool is_pinned:Bool can_be_edited:Bool can_be_forwarded:Bool can_be_saved:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_get_statistics:Bool can_get_message_thread:Bool can_get_viewers:Bool can_get_media_timestamp_links:Bool has_timestamped_media:Bool is_channel_post:Bool contains_unread_mention:Bool date:int32 edit_date:int32 forward_info:messageForwardInfo interaction_info:messageInteractionInfo reply_in_chat_id:int53 reply_to_message_id:int53 message_thread_id:int53 ttl:int32 ttl_expires_in:double via_bot_user_id:int53 author_signature:string media_album_id:int64 restriction_reason:string content:MessageContent reply_markup:ReplyMarkup = Message;
//@description Contains a list of messages @total_count Approximate total count of messages found @messages List of messages; messages may be null //@description Contains a list of messages @total_count Approximate total count of messages found @messages List of messages; messages may be null
messages total_count:int32 messages:vector<message> = Messages; messages total_count:int32 messages:vector<message> = Messages;
@ -976,6 +979,8 @@ videoChat group_call_id:int32 has_participants:Bool default_participant_id:Messa
//@permissions Actions that non-administrator chat members are allowed to take in the chat //@permissions Actions that non-administrator chat members are allowed to take in the chat
//@last_message Last message in the chat; may be null //@last_message Last message in the chat; may be null
//@positions Positions of the chat in chat lists //@positions Positions of the chat in chat lists
//@default_message_sender_id Default identifier of a user or chat that is chosen to send messages in the chat; may be null if the user can't change message sender
//@has_protected_content True, if chat content can't be saved locally, forwarded, or copied
//@is_marked_as_unread True, if the chat is marked as unread //@is_marked_as_unread True, if the chat is marked as unread
//@is_blocked True, if the chat is blocked by the current user and private messages from the chat can't be received //@is_blocked True, if the chat is blocked by the current user and private messages from the chat can't be received
//@has_scheduled_messages True, if the chat has scheduled messages //@has_scheduled_messages True, if the chat has scheduled messages
@ -996,7 +1001,7 @@ videoChat group_call_id:int32 has_participants:Bool default_participant_id:Messa
//@reply_markup_message_id Identifier of the message from which reply markup needs to be used; 0 if there is no default custom reply markup in the chat //@reply_markup_message_id Identifier of the message from which reply markup needs to be used; 0 if there is no default custom reply markup in the chat
//@draft_message A draft of a message in the chat; may be null //@draft_message A draft of a message in the chat; may be null
//@client_data Application-specific data associated with the chat. (For example, the chat scroll position or local chat notification settings can be stored here.) Persistent if the message database is used //@client_data Application-specific data associated with the chat. (For example, the chat scroll position or local chat notification settings can be stored here.) Persistent if the message database is used
chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector<chatPosition> is_marked_as_unread:Bool is_blocked:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings message_ttl_setting:int32 theme_name:string action_bar:ChatActionBar video_chat:videoChat pending_join_requests:chatJoinRequestsInfo reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat; chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector<chatPosition> default_message_sender_id:MessageSender has_protected_content:Bool is_marked_as_unread:Bool is_blocked:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings message_ttl_setting:int32 theme_name:string action_bar:ChatActionBar video_chat:videoChat pending_join_requests:chatJoinRequestsInfo reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat;
//@description Represents a list of chats @total_count Approximate total count of chats found @chat_ids List of chat identifiers //@description Represents a list of chats @total_count Approximate total count of chats found @chat_ids List of chat identifiers
chats total_count:int32 chat_ids:vector<int53> = Chats; chats total_count:int32 chat_ids:vector<int53> = Chats;
@ -1027,7 +1032,7 @@ chatActionBarReportSpam can_unarchive:Bool = ChatActionBar;
//@description The chat is a location-based supergroup, which can be reported as having unrelated location using the method reportChat with the reason chatReportReasonUnrelatedLocation //@description The chat is a location-based supergroup, which can be reported as having unrelated location using the method reportChat with the reason chatReportReasonUnrelatedLocation
chatActionBarReportUnrelatedLocation = ChatActionBar; chatActionBarReportUnrelatedLocation = ChatActionBar;
//@description The chat is a recently created group chat, to which new members can be invited //@description The chat is a recently created group chat to which new members can be invited
chatActionBarInviteMembers = ChatActionBar; chatActionBarInviteMembers = ChatActionBar;
//@description The chat is a private or secret chat, which can be reported using the method reportChat, or the other user can be blocked using the method toggleMessageSenderIsBlocked, or the other user can be added to the contact list using the method addContact //@description The chat is a private or secret chat, which can be reported using the method reportChat, or the other user can be blocked using the method toggleMessageSenderIsBlocked, or the other user can be added to the contact list using the method addContact
@ -1041,6 +1046,12 @@ chatActionBarAddContact = ChatActionBar;
//@description The chat is a private or secret chat with a mutual contact and the user's phone number can be shared with the other user using the method sharePhoneNumber //@description The chat is a private or secret chat with a mutual contact and the user's phone number can be shared with the other user using the method sharePhoneNumber
chatActionBarSharePhoneNumber = ChatActionBar; chatActionBarSharePhoneNumber = ChatActionBar;
//@description The chat is a private chat with an administrator of a chat to which the user sent join request
//@title Title of the chat to which the join request was sent
//@is_channel True, if the join request was sent to a channel chat
//@request_date Point in time (Unix timestamp) when the join request was sent
chatActionBarJoinRequest title:string is_channel:Bool request_date:int32 = ChatActionBar;
//@class KeyboardButtonType @description Describes a keyboard button type //@class KeyboardButtonType @description Describes a keyboard button type
@ -1084,6 +1095,9 @@ inlineKeyboardButtonTypeSwitchInline query:string in_current_chat:Bool = InlineK
//@description A button to buy something. This button must be in the first column and row of the keyboard and can be attached only to a message with content of the type messageInvoice //@description A button to buy something. This button must be in the first column and row of the keyboard and can be attached only to a message with content of the type messageInvoice
inlineKeyboardButtonTypeBuy = InlineKeyboardButtonType; inlineKeyboardButtonTypeBuy = InlineKeyboardButtonType;
//@description A button to open a chat with a user @user_id User identifier
inlineKeyboardButtonTypeUser user_id:int53 = InlineKeyboardButtonType;
//@description Represents a single button in an inline keyboard @text Text of the button @type Type of the button //@description Represents a single button in an inline keyboard @text Text of the button @type Type of the button
inlineKeyboardButton text:string type:InlineKeyboardButtonType = InlineKeyboardButton; inlineKeyboardButton text:string type:InlineKeyboardButtonType = InlineKeyboardButton;
@ -1868,8 +1882,8 @@ messagePassportDataSent types:vector<PassportElementType> = MessageContent;
//@description Telegram Passport data has been received; for bots only @elements List of received Telegram Passport elements @credentials Encrypted data credentials //@description Telegram Passport data has been received; for bots only @elements List of received Telegram Passport elements @credentials Encrypted data credentials
messagePassportDataReceived elements:vector<encryptedPassportElement> credentials:encryptedCredentials = MessageContent; messagePassportDataReceived elements:vector<encryptedPassportElement> credentials:encryptedCredentials = MessageContent;
//@description A user in the chat came within proximity alert range @traveler The user or chat, which triggered the proximity alert @watcher The user or chat, which subscribed for the proximity alert @distance The distance between the users //@description A user in the chat came within proximity alert range @traveler_id The identifier of a user or chat that triggered the proximity alert @watcher_id The identifier of a user or chat that subscribed for the proximity alert @distance The distance between the users
messageProximityAlertTriggered traveler:MessageSender watcher:MessageSender distance:int32 = MessageContent; messageProximityAlertTriggered traveler_id:MessageSender watcher_id:MessageSender distance:int32 = MessageContent;
//@description Message content that is not supported in the current TDLib version //@description Message content that is not supported in the current TDLib version
messageUnsupported = MessageContent; messageUnsupported = MessageContent;
@ -2022,7 +2036,7 @@ inputMessageInvoice invoice:invoice title:string description:string photo_url:st
//@description A message with a poll. Polls can't be sent to secret chats. Polls can be sent only to a private chat with a bot @question Poll question; 1-255 characters (up to 300 characters for bots) @options List of poll answer options, 2-10 strings 1-100 characters each //@description A message with a poll. Polls can't be sent to secret chats. Polls can be sent only to a private chat with a bot @question Poll question; 1-255 characters (up to 300 characters for bots) @options List of poll answer options, 2-10 strings 1-100 characters each
//@is_anonymous True, if the poll voters are anonymous. Non-anonymous polls can't be sent or forwarded to channels @type Type of the poll //@is_anonymous True, if the poll voters are anonymous. Non-anonymous polls can't be sent or forwarded to channels @type Type of the poll
//@open_period Amount of time the poll will be active after creation, in seconds; for bots only //@open_period Amount of time the poll will be active after creation, in seconds; for bots only
//@close_date Point in time (Unix timestamp) when the poll will be automatically closed; for bots only //@close_date Point in time (Unix timestamp) when the poll will automatically be closed; for bots only
//@is_closed True, if the poll needs to be sent already closed; for bots only //@is_closed True, if the poll needs to be sent already closed; for bots only
inputMessagePoll question:string options:vector<string> is_anonymous:Bool type:PollType open_period:int32 close_date:int32 is_closed:Bool = InputMessageContent; inputMessagePoll question:string options:vector<string> is_anonymous:Bool type:PollType open_period:int32 close_date:int32 is_closed:Bool = InputMessageContent;
@ -2353,10 +2367,12 @@ call id:int32 user_id:int53 is_outgoing:Bool is_video:Bool state:CallState = Cal
//@description Contains settings for the authentication of the user's phone number //@description Contains settings for the authentication of the user's phone number
//@allow_flash_call Pass true if the authentication code may be sent via flash call to the specified phone number //@allow_flash_call Pass true if the authentication code may be sent via a flash call to the specified phone number
//@allow_missed_call Pass true if the authentication code may be sent via a missed call to the specified phone number
//@is_current_phone_number Pass true if the authenticated phone number is used on the current device //@is_current_phone_number Pass true if the authenticated phone number is used on the current device
//@allow_sms_retriever_api For official applications only. True, if the application can use Android SMS Retriever API (requires Google Play Services >= 10.2) to automatically receive the authentication code from the SMS. See https://developers.google.com/identity/sms-retriever/ for more details //@allow_sms_retriever_api For official applications only. True, if the application can use Android SMS Retriever API (requires Google Play Services >= 10.2) to automatically receive the authentication code from the SMS. See https://developers.google.com/identity/sms-retriever/ for more details
phoneNumberAuthenticationSettings allow_flash_call:Bool is_current_phone_number:Bool allow_sms_retriever_api:Bool = PhoneNumberAuthenticationSettings; //@authentication_tokens List of authentication tokens, received in updateOption("authentication_token") in previously logged out sessions
phoneNumberAuthenticationSettings allow_flash_call:Bool allow_missed_call:Bool is_current_phone_number:Bool allow_sms_retriever_api:Bool authentication_tokens:vector<string> = PhoneNumberAuthenticationSettings;
//@description Represents a list of animations @animations List of animations //@description Represents a list of animations @animations List of animations
@ -2601,6 +2617,9 @@ chatEventMessageTtlSettingChanged old_message_ttl_setting:int32 new_message_ttl_
//@description The sign_messages setting of a channel was toggled @sign_messages New value of sign_messages //@description The sign_messages setting of a channel was toggled @sign_messages New value of sign_messages
chatEventSignMessagesToggled sign_messages:Bool = ChatEventAction; chatEventSignMessagesToggled sign_messages:Bool = ChatEventAction;
//@description The has_protected_content setting of a channel was toggled @has_protected_content New value of has_protected_content
chatEventHasProtectedContentToggled has_protected_content:Bool = ChatEventAction;
//@description The supergroup sticker set was changed @old_sticker_set_id Previous identifier of the chat sticker set; 0 if none @new_sticker_set_id New identifier of the chat sticker set; 0 if none //@description The supergroup sticker set was changed @old_sticker_set_id Previous identifier of the chat sticker set; 0 if none @new_sticker_set_id New identifier of the chat sticker set; 0 if none
chatEventStickerSetChanged old_sticker_set_id:int64 new_sticker_set_id:int64 = ChatEventAction; chatEventStickerSetChanged old_sticker_set_id:int64 new_sticker_set_id:int64 = ChatEventAction;
@ -2977,11 +2996,11 @@ notificationTypeNewCall call_id:int32 = NotificationType;
//@description New message was received through a push notification //@description New message was received through a push notification
//@message_id The message identifier. The message will not be available in the chat history, but the ID can be used in viewMessages, or as reply_to_message_id //@message_id The message identifier. The message will not be available in the chat history, but the ID can be used in viewMessages, or as reply_to_message_id
//@sender The sender of the message. Corresponding user or chat may be inaccessible //@sender_id Identifier of the sender of the message. Corresponding user or chat may be inaccessible
//@sender_name Name of the sender //@sender_name Name of the sender
//@is_outgoing True, if the message is outgoing //@is_outgoing True, if the message is outgoing
//@content Push message content //@content Push message content
notificationTypeNewPushMessage message_id:int53 sender:MessageSender sender_name:string is_outgoing:Bool content:PushMessageContent = NotificationType; notificationTypeNewPushMessage message_id:int53 sender_id:MessageSender sender_name:string is_outgoing:Bool content:PushMessageContent = NotificationType;
//@class NotificationGroupType @description Describes the type of notifications in a notification group //@class NotificationGroupType @description Describes the type of notifications in a notification group
@ -3111,16 +3130,18 @@ accountTtl days:int32 = AccountTtl;
//@description Contains information about one session in a Telegram application used by the current user. Sessions must be shown to the user in the returned order //@description Contains information about one session in a Telegram application used by the current user. Sessions must be shown to the user in the returned order
//@id Session identifier @is_current True, if this session is the current session //@id Session identifier @is_current True, if this session is the current session
//@is_password_pending True, if a password is needed to complete authorization of the session //@is_password_pending True, if a password is needed to complete authorization of the session
//@can_accept_secret_chats True, if incoming secret chats can be accepted by the session
//@can_accept_calls True, if incoming calls can be accepted by the session
//@api_id Telegram API identifier, as provided by the application @application_name Name of the application, as provided by the application //@api_id Telegram API identifier, as provided by the application @application_name Name of the application, as provided by the application
//@application_version The version of the application, as provided by the application @is_official_application True, if the application is an official application or uses the api_id of an official application //@application_version The version of the application, as provided by the application @is_official_application True, if the application is an official application or uses the api_id of an official application
//@device_model Model of the device the application has been run or is running on, as provided by the application @platform Operating system the application has been run or is running on, as provided by the application //@device_model Model of the device the application has been run or is running on, as provided by the application @platform Operating system the application has been run or is running on, as provided by the application
//@system_version Version of the operating system the application has been run or is running on, as provided by the application @log_in_date Point in time (Unix timestamp) when the user has logged in //@system_version Version of the operating system the application has been run or is running on, as provided by the application @log_in_date Point in time (Unix timestamp) when the user has logged in
//@last_active_date Point in time (Unix timestamp) when the session was last used @ip IP address from which the session was created, in human-readable format //@last_active_date Point in time (Unix timestamp) when the session was last used @ip IP address from which the session was created, in human-readable format
//@country A two-letter country code for the country from which the session was created, based on the IP address @region Region code from which the session was created, based on the IP address //@country A two-letter country code for the country from which the session was created, based on the IP address @region Region code from which the session was created, based on the IP address
session id:int64 is_current:Bool is_password_pending:Bool api_id:int32 application_name:string application_version:string is_official_application:Bool device_model:string platform:string system_version:string log_in_date:int32 last_active_date:int32 ip:string country:string region:string = Session; session id:int64 is_current:Bool is_password_pending:Bool can_accept_secret_chats:Bool can_accept_calls:Bool api_id:int32 application_name:string application_version:string is_official_application:Bool device_model:string platform:string system_version:string log_in_date:int32 last_active_date:int32 ip:string country:string region:string = Session;
//@description Contains a list of sessions @sessions List of sessions //@description Contains a list of sessions @sessions List of sessions @inactive_session_ttl_days Number of days of inactivity before sessions will automatically be terminated; 1-366 days
sessions sessions:vector<session> = Sessions; sessions sessions:vector<session> inactive_session_ttl_days:int32 = Sessions;
//@description Contains information about one website the current user is logged in with Telegram //@description Contains information about one website the current user is logged in with Telegram
@ -3479,6 +3500,9 @@ suggestedActionSeeTicksHint = SuggestedAction;
//@description Suggests the user to convert specified supergroup to a broadcast group @supergroup_id Supergroup identifier //@description Suggests the user to convert specified supergroup to a broadcast group @supergroup_id Supergroup identifier
suggestedActionConvertToBroadcastGroup supergroup_id:int53 = SuggestedAction; suggestedActionConvertToBroadcastGroup supergroup_id:int53 = SuggestedAction;
//@description Suggests the user to set a 2-step verification password to be able to log in again @authorization_delay The number of days to pass between consecutive authorizations if the user declines to set password
suggestedActionSetPassword authorization_delay:int32 = SuggestedAction;
//@description Contains a counter @count Count //@description Contains a counter @count Count
count count:int32 = Count; count count:int32 = Count;
@ -3722,6 +3746,12 @@ updateChatLastMessage chat_id:int53 last_message:message positions:vector<chatPo
//@description The position of a chat in a chat list has changed. Instead of this update updateChatLastMessage or updateChatDraftMessage might be sent @chat_id Chat identifier @position New chat position. If new order is 0, then the chat needs to be removed from the list //@description The position of a chat in a chat list has changed. Instead of this update updateChatLastMessage or updateChatDraftMessage might be sent @chat_id Chat identifier @position New chat position. If new order is 0, then the chat needs to be removed from the list
updateChatPosition chat_id:int53 position:chatPosition = Update; updateChatPosition chat_id:int53 position:chatPosition = Update;
//@description The default message sender that is chosen to send messages in a chat has changed @chat_id Chat identifier @default_message_sender_id New value of default_message_sender_id; may be null if the user can't change message sender
updateChatDefaultMessageSenderId chat_id:int53 default_message_sender_id:MessageSender = Update;
//@description A chat content was allowed or restricted for saving @chat_id Chat identifier @has_protected_content New value of has_protected_content
updateChatHasProtectedContent chat_id:int53 has_protected_content:Bool = Update;
//@description A chat was marked as unread or was read @chat_id Chat identifier @is_marked_as_unread New value of is_marked_as_unread //@description A chat was marked as unread or was read @chat_id Chat identifier @is_marked_as_unread New value of is_marked_as_unread
updateChatIsMarkedAsUnread chat_id:int53 is_marked_as_unread:Bool = Update; updateChatIsMarkedAsUnread chat_id:int53 is_marked_as_unread:Bool = Update;
@ -3803,8 +3833,8 @@ updateHavePendingNotifications have_delayed_notifications:Bool have_unreceived_n
//@from_cache True, if the messages are deleted only from the cache and can possibly be retrieved again in the future //@from_cache True, if the messages are deleted only from the cache and can possibly be retrieved again in the future
updateDeleteMessages chat_id:int53 message_ids:vector<int53> is_permanent:Bool from_cache:Bool = Update; updateDeleteMessages chat_id:int53 message_ids:vector<int53> is_permanent:Bool from_cache:Bool = Update;
//@description User activity in the chat has changed @chat_id Chat identifier @message_thread_id If not 0, a message thread identifier in which the action was performed @user_id Identifier of a user performing an action @action The action description //@description A message sender activity in the chat has changed @chat_id Chat identifier @message_thread_id If not 0, a message thread identifier in which the action was performed @sender_id Identifier of a message sender performing the action @action The action
updateUserChatAction chat_id:int53 message_thread_id:int53 user_id:int53 action:ChatAction = Update; updateChatAction chat_id:int53 message_thread_id:int53 sender_id:MessageSender action:ChatAction = Update;
//@description The user went online or offline @user_id User identifier @status New status of the user //@description The user went online or offline @user_id User identifier @status New status of the user
updateUserStatus user_id:int53 status:UserStatus = Update; updateUserStatus user_id:int53 status:UserStatus = Update;
@ -3824,16 +3854,16 @@ updateSupergroup supergroup:supergroup = Update;
//@description Some data of a secret chat has changed. This update is guaranteed to come before the secret chat identifier is returned to the application @secret_chat New data about the secret chat //@description Some data of a secret chat has changed. This update is guaranteed to come before the secret chat identifier is returned to the application @secret_chat New data about the secret chat
updateSecretChat secret_chat:secretChat = Update; updateSecretChat secret_chat:secretChat = Update;
//@description Some data from userFullInfo has been changed @user_id User identifier @user_full_info New full information about the user //@description Some data in userFullInfo has been changed @user_id User identifier @user_full_info New full information about the user
updateUserFullInfo user_id:int53 user_full_info:userFullInfo = Update; updateUserFullInfo user_id:int53 user_full_info:userFullInfo = Update;
//@description Some data from basicGroupFullInfo has been changed @basic_group_id Identifier of a basic group @basic_group_full_info New full information about the group //@description Some data in basicGroupFullInfo has been changed @basic_group_id Identifier of a basic group @basic_group_full_info New full information about the group
updateBasicGroupFullInfo basic_group_id:int53 basic_group_full_info:basicGroupFullInfo = Update; updateBasicGroupFullInfo basic_group_id:int53 basic_group_full_info:basicGroupFullInfo = Update;
//@description Some data from supergroupFullInfo has been changed @supergroup_id Identifier of the supergroup or channel @supergroup_full_info New full information about the supergroup //@description Some data in supergroupFullInfo has been changed @supergroup_id Identifier of the supergroup or channel @supergroup_full_info New full information about the supergroup
updateSupergroupFullInfo supergroup_id:int53 supergroup_full_info:supergroupFullInfo = Update; updateSupergroupFullInfo supergroup_id:int53 supergroup_full_info:supergroupFullInfo = Update;
//@description Service notification from the server. Upon receiving this the application must show a popup with the content of the notification //@description A service notification from the server was received. Upon receiving this the application must show a popup with the content of the notification
//@type Notification type. If type begins with "AUTH_KEY_DROP_", then two buttons "Cancel" and "Log out" must be shown under notification; if user presses the second, all local data must be destroyed using Destroy method //@type Notification type. If type begins with "AUTH_KEY_DROP_", then two buttons "Cancel" and "Log out" must be shown under notification; if user presses the second, all local data must be destroyed using Destroy method
//@content Notification content //@content Notification content
updateServiceNotification type:string content:MessageContent = Update; updateServiceNotification type:string content:MessageContent = Update;
@ -3986,7 +4016,7 @@ logStreamDefault = LogStream;
//@description The log is written to a file //@description The log is written to a file
//@path Path to the file to where the internal TDLib log will be written //@path Path to the file to where the internal TDLib log will be written
//@max_file_size The maximum size of the file to where the internal TDLib log is written before the file will be auto-rotated, in bytes //@max_file_size The maximum size of the file to where the internal TDLib log is written before the file will automatically be rotated, in bytes
//@redirect_stderr Pass true to additionally redirect stderr to the log file. Ignored on Windows //@redirect_stderr Pass true to additionally redirect stderr to the log file. Ignored on Windows
logStreamFile path:string max_file_size:int53 redirect_stderr:Bool = LogStream; logStreamFile path:string max_file_size:int53 redirect_stderr:Bool = LogStream;
@ -4036,7 +4066,7 @@ setAuthenticationPhoneNumber phone_number:string settings:phoneNumberAuthenticat
//@description Re-sends an authentication code to the user. Works only when the current authorization state is authorizationStateWaitCode, the next_code_type of the result is not null and the server-specified timeout has passed //@description Re-sends an authentication code to the user. Works only when the current authorization state is authorizationStateWaitCode, the next_code_type of the result is not null and the server-specified timeout has passed
resendAuthenticationCode = Ok; resendAuthenticationCode = Ok;
//@description Checks the authentication code. Works only when the current authorization state is authorizationStateWaitCode @code The verification code received via SMS, Telegram message, phone call, or flash call //@description Checks the authentication code. Works only when the current authorization state is authorizationStateWaitCode @code Authentication code to check
checkAuthenticationCode code:string = Ok; checkAuthenticationCode code:string = Ok;
//@description Requests QR code authentication by scanning a QR code on another logged in device. Works only when the current authorization state is authorizationStateWaitPhoneNumber, //@description Requests QR code authentication by scanning a QR code on another logged in device. Works only when the current authorization state is authorizationStateWaitPhoneNumber,
@ -4100,7 +4130,7 @@ getRecoveryEmailAddress password:string = RecoveryEmailAddress;
//-If new_recovery_email_address is the same as the email address that is currently set up, this call succeeds immediately and aborts all other requests waiting for an email confirmation @password Password of the current user @new_recovery_email_address New recovery email address //-If new_recovery_email_address is the same as the email address that is currently set up, this call succeeds immediately and aborts all other requests waiting for an email confirmation @password Password of the current user @new_recovery_email_address New recovery email address
setRecoveryEmailAddress password:string new_recovery_email_address:string = PasswordState; setRecoveryEmailAddress password:string new_recovery_email_address:string = PasswordState;
//@description Checks the 2-step verification recovery email address verification code @code Verification code //@description Checks the 2-step verification recovery email address verification code @code Verification code to check
checkRecoveryEmailAddressCode code:string = PasswordState; checkRecoveryEmailAddressCode code:string = PasswordState;
//@description Resends the 2-step verification recovery email address verification code //@description Resends the 2-step verification recovery email address verification code
@ -4281,13 +4311,13 @@ deleteChat chat_id:int53 = Ok;
//-(searchSecretMessages must be used instead), or without an enabled message database. For optimal performance, the number of returned messages is chosen by TDLib and can be smaller than the specified limit //-(searchSecretMessages must be used instead), or without an enabled message database. For optimal performance, the number of returned messages is chosen by TDLib and can be smaller than the specified limit
//@chat_id Identifier of the chat in which to search messages //@chat_id Identifier of the chat in which to search messages
//@query Query to search for //@query Query to search for
//@sender Sender of messages to search for; pass null to search for messages from any sender. Not supported in secret chats //@sender_id Identifier of the sender of messages to search for; pass null to search for messages from any sender. Not supported in secret chats
//@from_message_id Identifier of the message starting from which history must be fetched; use 0 to get results from the last message //@from_message_id Identifier of the message starting from which history must be fetched; use 0 to get results from the last message
//@offset Specify 0 to get results from exactly the from_message_id or a negative offset to get the specified message and some newer messages //@offset Specify 0 to get results from exactly the from_message_id or a negative offset to get the specified message and some newer messages
//@limit The maximum number of messages to be returned; must be positive and can't be greater than 100. If the offset is negative, the limit must be greater than -offset. For optimal performance, the number of returned messages is chosen by TDLib and can be smaller than the specified limit //@limit The maximum number of messages to be returned; must be positive and can't be greater than 100. If the offset is negative, the limit must be greater than -offset. For optimal performance, the number of returned messages is chosen by TDLib and can be smaller than the specified limit
//@filter Additional filter for messages to search; pass null to search for all messages //@filter Additional filter for messages to search; pass null to search for all messages
//@message_thread_id If not 0, only messages in the specified thread will be returned; supergroups only //@message_thread_id If not 0, only messages in the specified thread will be returned; supergroups only
searchChatMessages chat_id:int53 query:string sender:MessageSender from_message_id:int53 offset:int32 limit:int32 filter:SearchMessagesFilter message_thread_id:int53 = Messages; searchChatMessages chat_id:int53 query:string sender_id:MessageSender from_message_id:int53 offset:int32 limit:int32 filter:SearchMessagesFilter message_thread_id:int53 = Messages;
//@description Searches for messages in all chats except secret chats. Returns the results in reverse chronological order (i.e., in order of decreasing (date, chat_id, message_id)). //@description Searches for messages in all chats except secret chats. Returns the results in reverse chronological order (i.e., in order of decreasing (date, chat_id, message_id)).
//-For optimal performance, the number of returned messages is chosen by TDLib and can be smaller than the specified limit //-For optimal performance, the number of returned messages is chosen by TDLib and can be smaller than the specified limit
@ -4386,6 +4416,12 @@ getMessageEmbeddingCode chat_id:int53 message_id:int53 for_album:Bool = Text;
getMessageLinkInfo url:string = MessageLinkInfo; getMessageLinkInfo url:string = MessageLinkInfo;
//@description Returns list of message sender identifiers, which can be used to send messages in a chat @chat_id Chat identifier
getChatAvailableMessageSenders chat_id:int53 = MessageSenders;
//@description Changes default message sender that is chosen in a chat @chat_id Chat identifier @default_message_sender_id New default message sender in the chat
setChatDefaultMessageSender chat_id:int53 default_message_sender_id:MessageSender = Ok;
//@description Sends a message. Returns the sent message //@description Sends a message. Returns the sent message
//@chat_id Target chat //@chat_id Target chat
//@message_thread_id If not 0, a message thread identifier in which the message will be sent //@message_thread_id If not 0, a message thread identifier in which the message will be sent
@ -4437,17 +4473,17 @@ sendChatScreenshotTakenNotification chat_id:int53 = Ok;
//@description Adds a local message to a chat. The message is persistent across application restarts only if the message database is used. Returns the added message //@description Adds a local message to a chat. The message is persistent across application restarts only if the message database is used. Returns the added message
//@chat_id Target chat //@chat_id Target chat
//@sender The sender of the message //@sender_id Identifier of the sender of the message
//@reply_to_message_id Identifier of the message to reply to or 0 //@reply_to_message_id Identifier of the message to reply to or 0
//@disable_notification Pass true to disable notification for the message //@disable_notification Pass true to disable notification for the message
//@input_message_content The content of the message to be added //@input_message_content The content of the message to be added
addLocalMessage chat_id:int53 sender:MessageSender reply_to_message_id:int53 disable_notification:Bool input_message_content:InputMessageContent = Message; addLocalMessage chat_id:int53 sender_id:MessageSender reply_to_message_id:int53 disable_notification:Bool input_message_content:InputMessageContent = Message;
//@description Deletes messages @chat_id Chat identifier @message_ids Identifiers of the messages to be deleted @revoke Pass true to try to delete messages for all chat members. Always true for supergroups, channels and secret chats //@description Deletes messages @chat_id Chat identifier @message_ids Identifiers of the messages to be deleted @revoke Pass true to try to delete messages for all chat members. Always true for supergroups, channels and secret chats
deleteMessages chat_id:int53 message_ids:vector<int53> revoke:Bool = Ok; deleteMessages chat_id:int53 message_ids:vector<int53> revoke:Bool = Ok;
//@description Deletes all messages sent by the specified user to a chat. Supported only for supergroups; requires can_delete_messages administrator privileges @chat_id Chat identifier @user_id User identifier //@description Deletes all messages sent by the specified message sender in a chat. Supported only for supergroups; requires can_delete_messages administrator privileges @chat_id Chat identifier @sender_id Identifier of the sender of messages to delete
deleteChatMessagesFromUser chat_id:int53 user_id:int53 = Ok; deleteChatMessagesBySender chat_id:int53 sender_id:MessageSender = Ok;
//@description Deletes all messages between the specified dates in a chat. Supported only for private chats and basic groups. Messages sent in the last 30 seconds will not be deleted //@description Deletes all messages between the specified dates in a chat. Supported only for private chats and basic groups. Messages sent in the last 30 seconds will not be deleted
//@chat_id Chat identifier @min_date The minimum date of the messages to delete @max_date The maximum date of the messages to delete @revoke Pass true to try to delete chat messages for all users; private chats only //@chat_id Chat identifier @min_date The minimum date of the messages to delete @max_date The maximum date of the messages to delete @revoke Pass true to try to delete chat messages for all users; private chats only
@ -4774,6 +4810,10 @@ setChatDraftMessage chat_id:int53 message_thread_id:int53 draft_message:draftMes
//@chat_id Chat identifier @notification_settings New notification settings for the chat. If the chat is muted for more than 1 week, it is considered to be muted forever //@chat_id Chat identifier @notification_settings New notification settings for the chat. If the chat is muted for more than 1 week, it is considered to be muted forever
setChatNotificationSettings chat_id:int53 notification_settings:chatNotificationSettings = Ok; setChatNotificationSettings chat_id:int53 notification_settings:chatNotificationSettings = Ok;
//@description Changes the ability of users to save, forward, or copy chat content. Supported only for basic groups, supergroups and channels. Requires owner privileges
//@chat_id Chat identifier @has_protected_content True, if chat content can't be saved locally, forwarded, or copied
toggleChatHasProtectedContent chat_id:int53 has_protected_content:Bool = Ok;
//@description Changes the marked as unread state of a chat @chat_id Chat identifier @is_marked_as_unread New value of is_marked_as_unread //@description Changes the marked as unread state of a chat @chat_id Chat identifier @is_marked_as_unread New value of is_marked_as_unread
toggleChatIsMarkedAsUnread chat_id:int53 is_marked_as_unread:Bool = Ok; toggleChatIsMarkedAsUnread chat_id:int53 is_marked_as_unread:Bool = Ok;
@ -4887,7 +4927,7 @@ setPinnedChats chat_list:ChatList chat_ids:vector<int53> = Ok;
//@file_id Identifier of the file to download //@file_id Identifier of the file to download
//@priority Priority of the download (1-32). The higher the priority, the earlier the file will be downloaded. If the priorities of two files are equal, then the last one for which downloadFile was called will be downloaded first //@priority Priority of the download (1-32). The higher the priority, the earlier the file will be downloaded. If the priorities of two files are equal, then the last one for which downloadFile was called will be downloaded first
//@offset The starting position from which the file needs to be downloaded //@offset The starting position from which the file needs to be downloaded
//@limit Number of bytes which need to be downloaded starting from the "offset" position before the download will be automatically canceled; use 0 to download without a limit //@limit Number of bytes which need to be downloaded starting from the "offset" position before the download will automatically be canceled; use 0 to download without a limit
//@synchronous If false, this request returns file state just after the download has been started. If true, this request returns file state only after //@synchronous If false, this request returns file state just after the download has been started. If true, this request returns file state only after
//-the download has succeeded, has failed, has been canceled or a new downloadFile request with different offset/limit parameters was sent //-the download has succeeded, has failed, has been canceled or a new downloadFile request with different offset/limit parameters was sent
downloadFile file_id:int32 priority:int32 offset:int32 limit:int32 synchronous:Bool = File; downloadFile file_id:int32 priority:int32 offset:int32 limit:int32 synchronous:Bool = File;
@ -5018,11 +5058,14 @@ joinChatByInviteLink invite_link:string = Chat;
//@limit The maximum number of chat join requests to return //@limit The maximum number of chat join requests to return
getChatJoinRequests chat_id:int53 invite_link:string query:string offset_request:chatJoinRequest limit:int32 = ChatJoinRequests; getChatJoinRequests chat_id:int53 invite_link:string query:string offset_request:chatJoinRequest limit:int32 = ChatJoinRequests;
//@description Approves pending join request in a chat @chat_id Chat identifier @user_id Identifier of the user, which request will be approved //@description Handles a pending join request in a chat @chat_id Chat identifier @user_id Identifier of the user that sent the request @approve True, if the request is approved. Otherwise the request is declived
approveChatJoinRequest chat_id:int53 user_id:int53 = Ok; processChatJoinRequest chat_id:int53 user_id:int53 approve:Bool = Ok;
//@description Declines pending join request in a chat @chat_id Chat identifier @user_id Identifier of the user, which request will be declined //@description Handles all pending join requests for a given link in a chat
declineChatJoinRequest chat_id:int53 user_id:int53 = Ok; //@chat_id Chat identifier
//@invite_link Invite link for which to process join requests. If empty, all join requests will be processed. Requires administrator privileges and can_invite_users right in the chat for own links and owner privileges for other links
//@approve True, if the requests are approved. Otherwise the requests are declived
processChatJoinRequests chat_id:int53 invite_link:string approve:Bool = Ok;
//@description Creates a new call @user_id Identifier of the user to be called @protocol The call protocols supported by the application @is_video True, if a video call needs to be created //@description Creates a new call @user_id Identifier of the user to be called @protocol The call protocols supported by the application @is_video True, if a video call needs to be created
@ -5157,8 +5200,8 @@ discardGroupCall group_call_id:int32 = Ok;
getGroupCallStreamSegment group_call_id:int32 time_offset:int53 scale:int32 channel_id:int32 video_quality:GroupCallVideoQuality = FilePart; getGroupCallStreamSegment group_call_id:int32 time_offset:int53 scale:int32 channel_id:int32 video_quality:GroupCallVideoQuality = FilePart;
//@description Changes the block state of a message sender. Currently, only users and supergroup chats can be blocked @sender Message Sender @is_blocked New value of is_blocked //@description Changes the block state of a message sender. Currently, only users and supergroup chats can be blocked @sender_id Identifier of a message sender to block/unblock @is_blocked New value of is_blocked
toggleMessageSenderIsBlocked sender:MessageSender is_blocked:Bool = Ok; toggleMessageSenderIsBlocked sender_id:MessageSender is_blocked:Bool = Ok;
//@description Blocks an original sender of a message in the Replies chat //@description Blocks an original sender of a message in the Replies chat
//@message_id The identifier of an incoming message in the Replies chat //@message_id The identifier of an incoming message in the Replies chat
@ -5337,7 +5380,7 @@ changePhoneNumber phone_number:string settings:phoneNumberAuthenticationSettings
//@description Re-sends the authentication code sent to confirm a new phone number for the current user. Works only if the previously received authenticationCodeInfo next_code_type was not null and the server-specified timeout has passed //@description Re-sends the authentication code sent to confirm a new phone number for the current user. Works only if the previously received authenticationCodeInfo next_code_type was not null and the server-specified timeout has passed
resendChangePhoneNumberCode = AuthenticationCodeInfo; resendChangePhoneNumberCode = AuthenticationCodeInfo;
//@description Checks the authentication code sent to confirm a new phone number of the user @code Verification code received by SMS, phone call or flash call //@description Checks the authentication code sent to confirm a new phone number of the user @code Authentication code to check
checkChangePhoneNumberCode code:string = Ok; checkChangePhoneNumberCode code:string = Ok;
@ -5367,6 +5410,15 @@ terminateSession session_id:int64 = Ok;
//@description Terminates all other sessions of the current user //@description Terminates all other sessions of the current user
terminateAllOtherSessions = Ok; terminateAllOtherSessions = Ok;
//@description Toggles whether a session can accept incoming calls @session_id Session identifier @can_accept_calls True, if incoming calls can be accepted by the session
toggleSessionCanAcceptCalls session_id:int64 can_accept_calls:Bool = Ok;
//@description Toggles whether a session can accept incoming secret chats @session_id Session identifier @can_accept_secret_chats True, if incoming secret chats can be accepted by the session
toggleSessionCanAcceptSecretChats session_id:int64 can_accept_secret_chats:Bool = Ok;
//@description Changes the period of inactivity after which sessions will automatically be terminated @inactive_session_ttl_days New number of days of inactivity before sessions will be automatically terminated; 1-366 days
setInactiveSessionTtl inactive_session_ttl_days:int32 = Ok;
//@description Returns all website where the current user used Telegram to log in //@description Returns all website where the current user used Telegram to log in
getConnectedWebsites = ConnectedWebsites; getConnectedWebsites = ConnectedWebsites;
@ -5384,7 +5436,7 @@ setSupergroupUsername supergroup_id:int53 username:string = Ok;
//@description Changes the sticker set of a supergroup; requires can_change_info administrator right @supergroup_id Identifier of the supergroup @sticker_set_id New value of the supergroup sticker set identifier. Use 0 to remove the supergroup sticker set //@description Changes the sticker set of a supergroup; requires can_change_info administrator right @supergroup_id Identifier of the supergroup @sticker_set_id New value of the supergroup sticker set identifier. Use 0 to remove the supergroup sticker set
setSupergroupStickerSet supergroup_id:int53 sticker_set_id:int64 = Ok; setSupergroupStickerSet supergroup_id:int53 sticker_set_id:int64 = Ok;
//@description Toggles sender signatures messages sent in a channel; requires can_change_info administrator right @supergroup_id Identifier of the channel @sign_messages New value of sign_messages //@description Toggles whether sender signature is added to sent messages in a channel; requires can_change_info administrator right @supergroup_id Identifier of the channel @sign_messages New value of sign_messages
toggleSupergroupSignMessages supergroup_id:int53 sign_messages:Bool = Ok; toggleSupergroupSignMessages supergroup_id:int53 sign_messages: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 //@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
@ -5393,8 +5445,8 @@ toggleSupergroupIsAllHistoryAvailable supergroup_id:int53 is_all_history_availab
//@description Upgrades supergroup to a broadcast group; requires owner privileges in the supergroup @supergroup_id Identifier of the supergroup //@description Upgrades supergroup to a broadcast group; requires owner privileges in the supergroup @supergroup_id Identifier of the supergroup
toggleSupergroupIsBroadcastGroup supergroup_id:int53 = Ok; toggleSupergroupIsBroadcastGroup supergroup_id:int53 = Ok;
//@description Reports some messages from a user in a supergroup as spam; requires administrator rights in the supergroup @supergroup_id Supergroup identifier @user_id User identifier @message_ids Identifiers of messages sent in the supergroup by the user. This list must be non-empty //@description Reports some messages from a message sender in a supergroup as spam; requires administrator rights in the supergroup @supergroup_id Supergroup identifier @message_ids Identifiers of messages sent in the supergroup. All messages must be sent by the same sender. This list must be non-empty
reportSupergroupSpam supergroup_id:int53 user_id:int53 message_ids:vector<int53> = Ok; reportSupergroupSpam supergroup_id:int53 message_ids:vector<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 //@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 //@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
@ -5635,7 +5687,7 @@ sendPhoneNumberVerificationCode phone_number:string settings:phoneNumberAuthenti
//@description Re-sends the code to verify a phone number to be added to a user's Telegram Passport //@description Re-sends the code to verify a phone number to be added to a user's Telegram Passport
resendPhoneNumberVerificationCode = AuthenticationCodeInfo; resendPhoneNumberVerificationCode = AuthenticationCodeInfo;
//@description Checks the phone number verification code for Telegram Passport @code Verification code //@description Checks the phone number verification code for Telegram Passport @code Verification code to check
checkPhoneNumberVerificationCode code:string = Ok; checkPhoneNumberVerificationCode code:string = Ok;
@ -5645,7 +5697,7 @@ sendEmailAddressVerificationCode email_address:string = EmailAddressAuthenticati
//@description Re-sends the code to verify an email address to be added to a user's Telegram Passport //@description Re-sends the code to verify an email address to be added to a user's Telegram Passport
resendEmailAddressVerificationCode = EmailAddressAuthenticationCodeInfo; resendEmailAddressVerificationCode = EmailAddressAuthenticationCodeInfo;
//@description Checks the email address verification code for Telegram Passport @code Verification code //@description Checks the email address verification code for Telegram Passport @code Verification code to check
checkEmailAddressVerificationCode code:string = Ok; checkEmailAddressVerificationCode code:string = Ok;
@ -5666,7 +5718,7 @@ sendPhoneNumberConfirmationCode hash:string phone_number:string settings:phoneNu
//@description Resends phone number confirmation code //@description Resends phone number confirmation code
resendPhoneNumberConfirmationCode = AuthenticationCodeInfo; resendPhoneNumberConfirmationCode = AuthenticationCodeInfo;
//@description Checks phone number confirmation code @code The phone number confirmation code //@description Checks phone number confirmation code @code Confirmation code to check
checkPhoneNumberConfirmationCode code:string = Ok; checkPhoneNumberConfirmationCode code:string = Ok;

View File

@ -113,13 +113,13 @@ userStatusLastWeek#7bf09fc = UserStatus;
userStatusLastMonth#77ebc742 = UserStatus; userStatusLastMonth#77ebc742 = UserStatus;
chatEmpty#29562865 id:long = Chat; chatEmpty#29562865 id:long = Chat;
chat#41cbf256 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; chat#41cbf256 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;
chatForbidden#6592a1a7 id:long title:string = Chat; chatForbidden#6592a1a7 id:long title:string = Chat;
channel#8261ac61 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat; channel#8261ac61 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat;
channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat; 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#46a6ffb4 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> = ChatFull; chatFull#46a6ffb4 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> = ChatFull;
channelFull#59cff963 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 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> = ChatFull; channelFull#56662e2e 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 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 = ChatFull;
chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant; chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant;
chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant; chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant;
@ -132,7 +132,7 @@ chatPhotoEmpty#37c1011c = ChatPhoto;
chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto;
messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message; messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message;
message#85d6cbe2 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true id:int from_id:flags.8?Peer peer_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long restriction_reason:flags.22?Vector<RestrictionReason> ttl_period:flags.25?int = Message; message#85d6cbe2 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true id:int from_id:flags.8?Peer peer_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long restriction_reason:flags.22?Vector<RestrictionReason> ttl_period:flags.25?int = Message;
messageService#2b085862 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction ttl_period:flags.25?int = Message; messageService#2b085862 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction ttl_period:flags.25?int = Message;
messageMediaEmpty#3ded6320 = MessageMedia; messageMediaEmpty#3ded6320 = MessageMedia;
@ -198,7 +198,7 @@ geoPoint#b2a2f663 flags:# long:double lat:double access_hash:long accuracy_radiu
auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode;
auth.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization; auth.authorization#33fb7bb8 flags:# setup_password_required:flags.1?true otherwise_relogin_days:flags.1?int tmp_sessions:flags.0?int user:User = auth.Authorization;
auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization; auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization;
auth.exportedAuthorization#b434e2b8 id:long bytes:bytes = auth.ExportedAuthorization; auth.exportedAuthorization#b434e2b8 id:long bytes:bytes = auth.ExportedAuthorization;
@ -212,7 +212,7 @@ inputPeerNotifySettings#9c3d198e flags:# show_previews:flags.0?Bool silent:flags
peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = PeerNotifySettings; peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = PeerNotifySettings;
peerSettings#733f2961 flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true autoarchived:flags.7?true invite_members:flags.8?true geo_distance:flags.6?int = PeerSettings; peerSettings#a518110d flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true autoarchived:flags.7?true invite_members:flags.8?true request_chat_broadcast:flags.10?true geo_distance:flags.6?int request_chat_title:flags.9?string request_chat_date:flags.9?int = PeerSettings;
wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper; wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper;
wallPaperNoFile#e0804116 id:long flags:# default:flags.1?true dark:flags.4?true settings:flags.2?WallPaperSettings = WallPaper; wallPaperNoFile#e0804116 id:long flags:# default:flags.1?true dark:flags.4?true settings:flags.2?WallPaperSettings = WallPaper;
@ -226,7 +226,7 @@ inputReportReasonCopyright#9b89f93a = ReportReason;
inputReportReasonGeoIrrelevant#dbd4feed = ReportReason; inputReportReasonGeoIrrelevant#dbd4feed = ReportReason;
inputReportReasonFake#f5ddd6e7 = ReportReason; inputReportReasonFake#f5ddd6e7 = ReportReason;
userFull#d697ff05 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true user:User about:flags.1?string settings:PeerSettings profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string = UserFull; userFull#cf366521 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true id:long about:flags.1?string settings:PeerSettings profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string = UserFull;
contact#145ade0b user_id:long mutual:Bool = Contact; contact#145ade0b user_id:long mutual:Bool = Contact;
@ -528,9 +528,9 @@ webPagePending#c586da1c id:long date:int = WebPage;
webPage#e89c45b2 flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector<WebPageAttribute> = WebPage; webPage#e89c45b2 flags:# id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector<WebPageAttribute> = WebPage;
webPageNotModified#7311ca11 flags:# cached_page_views:flags.0?int = WebPage; webPageNotModified#7311ca11 flags:# cached_page_views:flags.0?int = WebPage;
authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true encrypted_requests_disabled:flags.3?true call_requests_disabled:flags.4?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization;
account.authorizations#1250abde authorizations:Vector<Authorization> = account.Authorizations; account.authorizations#4bff8ea0 authorization_ttl_days:int authorizations:Vector<Authorization> = account.Authorizations;
account.password#185b184f flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes pending_reset_date:flags.5?int = account.Password; account.password#185b184f flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes pending_reset_date:flags.5?int = account.Password;
@ -558,6 +558,7 @@ inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet;
stickerSet#d7df217a flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int count:int hash:int = StickerSet; stickerSet#d7df217a flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int count:int hash:int = StickerSet;
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
messages.stickerSetNotModified#d3f924eb = messages.StickerSet;
botCommand#c27ac8c7 command:string description:string = BotCommand; botCommand#c27ac8c7 command:string description:string = BotCommand;
@ -574,6 +575,8 @@ keyboardButtonBuy#afd93fbb text:string = KeyboardButton;
keyboardButtonUrlAuth#10b78d29 flags:# text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton; keyboardButtonUrlAuth#10b78d29 flags:# text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton;
inputKeyboardButtonUrlAuth#d02e7fd4 flags:# request_write_access:flags.0?true text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton; inputKeyboardButtonUrlAuth#d02e7fd4 flags:# request_write_access:flags.0?true text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton;
keyboardButtonRequestPoll#bbc7515d flags:# quiz:flags.0?Bool text:string = KeyboardButton; keyboardButtonRequestPoll#bbc7515d flags:# quiz:flags.0?Bool text:string = KeyboardButton;
inputKeyboardButtonUserProfile#e988037b text:string user_id:InputUser = KeyboardButton;
keyboardButtonUserProfile#308660c1 text:string user_id:long = KeyboardButton;
keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow; keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
@ -618,7 +621,7 @@ channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter;
channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector<MessageRange> = ChannelMessagesFilter; channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector<MessageRange> = ChannelMessagesFilter;
channelParticipant#c00c07c0 user_id:long date:int = ChannelParticipant; channelParticipant#c00c07c0 user_id:long date:int = ChannelParticipant;
channelParticipantSelf#35a8bfa7 flags:# via_invite:flags.0?true user_id:long inviter_id:long date:int = ChannelParticipant; channelParticipantSelf#35a8bfa7 flags:# via_request:flags.0?true user_id:long inviter_id:long date:int = ChannelParticipant;
channelParticipantCreator#2fe601d3 flags:# user_id:long admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant; channelParticipantCreator#2fe601d3 flags:# user_id:long admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant;
channelParticipantAdmin#34c3bb53 flags:# can_edit:flags.0?true self:flags.1?true user_id:long inviter_id:flags.1?long promoted_by:long date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant; channelParticipantAdmin#34c3bb53 flags:# can_edit:flags.0?true self:flags.1?true user_id:long inviter_id:flags.1?long promoted_by:long date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant;
channelParticipantBanned#6df8014e flags:# left:flags.0?true peer:Peer kicked_by:long date:int banned_rights:ChatBannedRights = ChannelParticipant; channelParticipantBanned#6df8014e flags:# left:flags.0?true peer:Peer kicked_by:long date:int banned_rights:ChatBannedRights = ChannelParticipant;
@ -675,11 +678,13 @@ messageFwdHeader#5f777dce flags:# imported:flags.7?true from_id:flags.0?Peer fro
auth.codeTypeSms#72a3158c = auth.CodeType; auth.codeTypeSms#72a3158c = auth.CodeType;
auth.codeTypeCall#741cd3e3 = auth.CodeType; auth.codeTypeCall#741cd3e3 = auth.CodeType;
auth.codeTypeFlashCall#226ccefb = auth.CodeType; auth.codeTypeFlashCall#226ccefb = auth.CodeType;
auth.codeTypeMissedCall#d61ad6ee = auth.CodeType;
auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType;
auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType;
auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType;
auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType;
auth.sentCodeTypeMissedCall#82006484 prefix: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; 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;
@ -902,12 +907,14 @@ channelAdminLogEventActionExportedInviteEdit#e90ebb59 prev_invite:ExportedChatIn
channelAdminLogEventActionParticipantVolume#3e7f6847 participant:GroupCallParticipant = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantVolume#3e7f6847 participant:GroupCallParticipant = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeHistoryTTL#6e941a38 prev_value:int new_value:int = ChannelAdminLogEventAction; channelAdminLogEventActionChangeHistoryTTL#6e941a38 prev_value:int new_value:int = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantJoinByRequest#afb6144a invite:ExportedChatInvite approved_by:long = ChannelAdminLogEventAction; channelAdminLogEventActionParticipantJoinByRequest#afb6144a invite:ExportedChatInvite approved_by:long = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleNoForwards#cb2ac766 new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionSendMessage#278f2868 message:Message = ChannelAdminLogEventAction;
channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
channels.adminLogResults#ed8af74d events:Vector<ChannelAdminLogEvent> chats:Vector<Chat> users:Vector<User> = channels.AdminLogResults; channels.adminLogResults#ed8af74d events:Vector<ChannelAdminLogEvent> chats:Vector<Chat> users:Vector<User> = channels.AdminLogResults;
channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true = ChannelAdminLogEventsFilter; channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true = ChannelAdminLogEventsFilter;
popularContact#5ce14175 client_id:long importers:int = PopularContact; popularContact#5ce14175 client_id:long importers:int = PopularContact;
@ -1076,7 +1083,7 @@ inputWallPaperNoFile#967a462e id:long = InputWallPaper;
account.wallPapersNotModified#1c199183 = account.WallPapers; account.wallPapersNotModified#1c199183 = account.WallPapers;
account.wallPapers#cdc3858c hash:long wallpapers:Vector<WallPaper> = account.WallPapers; account.wallPapers#cdc3858c hash:long wallpapers:Vector<WallPaper> = account.WallPapers;
codeSettings#debebe83 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true = CodeSettings; codeSettings#8a6469c2 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true allow_missed_call:flags.5?true logout_tokens:flags.6?Vector<bytes> = CodeSettings;
wallPaperSettings#1dc1bca4 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int = WallPaperSettings; wallPaperSettings#1dc1bca4 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int = WallPaperSettings;
@ -1277,6 +1284,14 @@ searchResultPosition#7f648b67 msg_id:int date:int offset:int = SearchResultsPosi
messages.searchResultsPositions#53b22baf count:int positions:Vector<SearchResultsPosition> = messages.SearchResultsPositions; messages.searchResultsPositions#53b22baf count:int positions:Vector<SearchResultsPosition> = messages.SearchResultsPositions;
channels.sendAsPeers#8356cda9 peers:Vector<Peer> chats:Vector<Chat> users:Vector<User> = channels.SendAsPeers;
users.userFull#3b6d152e full_user:UserFull chats:Vector<Chat> users:Vector<User> = users.UserFull;
messages.peerSettings#6880b94d settings:PeerSettings chats:Vector<Chat> users:Vector<User> = messages.PeerSettings;
auth.loggedOut#c3a2835f flags:# future_auth_token:flags.0?bytes = auth.LoggedOut;
---functions--- ---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@ -1290,7 +1305,7 @@ invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X;
auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode; auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode;
auth.signUp#80eee427 phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization; auth.signUp#80eee427 phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization;
auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization; auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization;
auth.logOut#5717da40 = Bool; auth.logOut#3e72ba19 = auth.LoggedOut;
auth.resetAuthorizations#9fab0d1a = Bool; auth.resetAuthorizations#9fab0d1a = Bool;
auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization;
auth.importAuthorization#a57a7dad id:long bytes:bytes = auth.Authorization; auth.importAuthorization#a57a7dad id:long bytes:bytes = auth.Authorization;
@ -1378,9 +1393,11 @@ account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:Re
account.resetPassword#9308ce1b = account.ResetPasswordResult; account.resetPassword#9308ce1b = account.ResetPasswordResult;
account.declinePasswordReset#4c9409f6 = Bool; account.declinePasswordReset#4c9409f6 = Bool;
account.getChatThemes#d638de89 hash:long = account.Themes; account.getChatThemes#d638de89 hash:long = account.Themes;
account.setAuthorizationTTL#bf899aa0 authorization_ttl_days:int = Bool;
account.changeAuthorizationSettings#40f48462 flags:# hash:long encrypted_requests_disabled:flags.0?Bool call_requests_disabled:flags.1?Bool = Bool;
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>; users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
users.getFullUser#ca30a5b1 id:InputUser = UserFull; users.getFullUser#b60f5918 id:InputUser = users.UserFull;
users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector<SecureValueError> = Bool; users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector<SecureValueError> = Bool;
contacts.getContactIDs#7adc669d hash:long = Vector<int>; contacts.getContactIDs#7adc669d hash:long = Vector<int>;
@ -1413,11 +1430,11 @@ messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?t
messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>; messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool; messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool;
messages.sendMessage#520c3870 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates; messages.sendMessage#d9d75a4 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
messages.sendMedia#3491eba9 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates; messages.sendMedia#e25ff8e0 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
messages.forwardMessages#d9fee60e flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer schedule_date:flags.10?int = Updates; messages.forwardMessages#cc30290b flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.reportSpam#cf1592db peer:InputPeer = Bool;
messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; messages.getPeerSettings#efd9a6a2 peer:InputPeer = messages.PeerSettings;
messages.report#8953ab4e peer:InputPeer id:Vector<int> reason:ReportReason message:string = Bool; messages.report#8953ab4e peer:InputPeer id:Vector<int> reason:ReportReason message:string = Bool;
messages.getChats#49e9528f id:Vector<long> = messages.Chats; messages.getChats#49e9528f id:Vector<long> = messages.Chats;
messages.getFullChat#aeb00b34 chat_id:long = messages.ChatFull; messages.getFullChat#aeb00b34 chat_id:long = messages.ChatFull;
@ -1444,7 +1461,7 @@ messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vect
messages.exportChatInvite#a02ce5d5 flags:# legacy_revoke_permanent:flags.2?true request_needed:flags.3?true peer:InputPeer expire_date:flags.0?int usage_limit:flags.1?int title:flags.4?string = ExportedChatInvite; messages.exportChatInvite#a02ce5d5 flags:# legacy_revoke_permanent:flags.2?true request_needed:flags.3?true peer:InputPeer expire_date:flags.0?int usage_limit:flags.1?int title:flags.4?string = ExportedChatInvite;
messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite;
messages.importChatInvite#6c50051c hash:string = Updates; messages.importChatInvite#6c50051c hash:string = Updates;
messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; messages.getStickerSet#c8a0ec74 stickerset:InputStickerSet hash:int = messages.StickerSet;
messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult;
messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool;
messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates;
@ -1458,7 +1475,7 @@ messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs;
messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool;
messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults;
messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool; messages.setInlineBotResults#eb5ea206 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM = Bool;
messages.sendInlineBotResult#220815b0 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string schedule_date:flags.10?int = Updates; messages.sendInlineBotResult#7aa11297 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
messages.editMessage#48f71778 flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.15?int = Updates; messages.editMessage#48f71778 flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.15?int = Updates;
messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool; messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool;
@ -1494,7 +1511,7 @@ messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool;
messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory; messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory;
messages.getRecentLocations#702a40e0 peer:InputPeer limit:int hash:long = messages.Messages; messages.getRecentLocations#702a40e0 peer:InputPeer limit:int hash:long = messages.Messages;
messages.sendMultiMedia#cc0110cb flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector<InputSingleMedia> schedule_date:flags.10?int = Updates; messages.sendMultiMedia#f803138f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector<InputSingleMedia> schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile;
messages.searchStickerSets#35705b8a flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; messages.searchStickerSets#35705b8a flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets;
messages.getSplitRanges#1cff7e08 = Vector<MessageRange>; messages.getSplitRanges#1cff7e08 = Vector<MessageRange>;
@ -1550,6 +1567,9 @@ messages.getMessageReadParticipants#2c6f97b7 peer:InputPeer msg_id:int = Vector<
messages.getSearchResultsCalendar#49f0bde9 peer:InputPeer filter:MessagesFilter offset_id:int offset_date:int = messages.SearchResultsCalendar; messages.getSearchResultsCalendar#49f0bde9 peer:InputPeer filter:MessagesFilter offset_id:int offset_date:int = messages.SearchResultsCalendar;
messages.getSearchResultsPositions#6e9583a3 peer:InputPeer filter:MessagesFilter offset_id:int limit:int = messages.SearchResultsPositions; messages.getSearchResultsPositions#6e9583a3 peer:InputPeer filter:MessagesFilter offset_id:int limit:int = messages.SearchResultsPositions;
messages.hideChatJoinRequest#7fe7e815 flags:# approved:flags.0?true peer:InputPeer user_id:InputUser = Updates; messages.hideChatJoinRequest#7fe7e815 flags:# approved:flags.0?true peer:InputPeer user_id:InputUser = Updates;
messages.hideAllChatJoinRequests#e085f4ea flags:# approved:flags.0?true peer:InputPeer link:flags.1?string = Updates;
messages.toggleNoForwards#b11eafa2 peer:InputPeer enabled:Bool = Updates;
messages.saveDefaultSendAs#ccfddf96 peer:InputPeer send_as:InputPeer = Bool;
updates.getState#edd4882a = updates.State; updates.getState#edd4882a = updates.State;
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
@ -1594,8 +1614,7 @@ help.getCountriesList#735787a8 lang_code:string hash:int = help.CountriesList;
channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages;
channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory; channels.reportSpam#f44a8315 channel:InputChannel participant:InputPeer id:Vector<int> = Bool;
channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector<int> = Bool;
channels.getMessages#ad8c9a23 channel:InputChannel id:Vector<InputMessage> = messages.Messages; channels.getMessages#ad8c9a23 channel:InputChannel id:Vector<InputMessage> = messages.Messages;
channels.getParticipants#77ced9d0 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:long = channels.ChannelParticipants; channels.getParticipants#77ced9d0 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:long = channels.ChannelParticipants;
channels.getParticipant#a0ab6cc6 channel:InputChannel participant:InputPeer = channels.ChannelParticipant; channels.getParticipant#a0ab6cc6 channel:InputChannel participant:InputPeer = channels.ChannelParticipant;
@ -1630,6 +1649,8 @@ channels.getInactiveChannels#11e831ee = messages.InactiveChats;
channels.convertToGigagroup#b290c69 channel:InputChannel = Updates; channels.convertToGigagroup#b290c69 channel:InputChannel = Updates;
channels.viewSponsoredMessage#beaedb94 channel:InputChannel random_id:bytes = Bool; channels.viewSponsoredMessage#beaedb94 channel:InputChannel random_id:bytes = Bool;
channels.getSponsoredMessages#ec210fbf channel:InputChannel = messages.SponsoredMessages; channels.getSponsoredMessages#ec210fbf channel:InputChannel = messages.SponsoredMessages;
channels.getSendAs#dc770ee peer:InputPeer = channels.SendAsPeers;
channels.deleteParticipantHistory#367544db channel:InputChannel participant:InputPeer = messages.AffectedHistory;
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;

View File

@ -32,7 +32,8 @@ static td_api::object_ptr<td_api::session> convert_authorization_object(
tl_object_ptr<telegram_api::authorization> &&authorization) { tl_object_ptr<telegram_api::authorization> &&authorization) {
CHECK(authorization != nullptr); CHECK(authorization != nullptr);
return td_api::make_object<td_api::session>( return td_api::make_object<td_api::session>(
authorization->hash_, authorization->current_, authorization->password_pending_, authorization->api_id_, authorization->hash_, authorization->current_, authorization->password_pending_,
!authorization->encrypted_requests_disabled_, !authorization->call_requests_disabled_, authorization->api_id_,
authorization->app_name_, authorization->app_version_, authorization->official_app_, authorization->device_model_, authorization->app_name_, authorization->app_version_, authorization->official_app_, authorization->device_model_,
authorization->platform_, authorization->system_version_, authorization->date_created_, authorization->platform_, authorization->system_version_, authorization->date_created_,
authorization->date_active_, authorization->ip_, authorization->country_, authorization->region_); authorization->date_active_, authorization->ip_, authorization->country_, authorization->region_);
@ -145,8 +146,14 @@ class GetAuthorizationsQuery final : public Td::ResultHandler {
auto ptr = result_ptr.move_as_ok(); auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for GetAuthorizationsQuery: " << to_string(ptr); LOG(INFO) << "Receive result for GetAuthorizationsQuery: " << to_string(ptr);
auto results = auto ttl_days = ptr->authorization_ttl_days_;
td_api::make_object<td_api::sessions>(transform(std::move(ptr->authorizations_), convert_authorization_object)); if (ttl_days <= 0 || ttl_days > 366) {
LOG(ERROR) << "Receive invalid inactive sessions TTL " << ttl_days;
ttl_days = 180;
}
auto results = td_api::make_object<td_api::sessions>(
transform(std::move(ptr->authorizations_), convert_authorization_object), ttl_days);
std::sort(results->sessions_.begin(), results->sessions_.end(), std::sort(results->sessions_.begin(), results->sessions_.end(),
[](const td_api::object_ptr<td_api::session> &lhs, const td_api::object_ptr<td_api::session> &rhs) { [](const td_api::object_ptr<td_api::session> &lhs, const td_api::object_ptr<td_api::session> &rhs) {
if (lhs->is_current_ != rhs->is_current_) { if (lhs->is_current_ != rhs->is_current_) {
@ -221,6 +228,69 @@ class ResetAuthorizationsQuery final : public Td::ResultHandler {
} }
}; };
class ChangeAuthorizationSettingsQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
public:
explicit ChangeAuthorizationSettingsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(int64 hash, bool set_encrypted_requests_disabled, bool encrypted_requests_disabled,
bool set_call_requests_disabled, bool call_requests_disabled) {
int32 flags = 0;
if (set_encrypted_requests_disabled) {
flags |= telegram_api::account_changeAuthorizationSettings::ENCRYPTED_REQUESTS_DISABLED_MASK;
}
if (set_call_requests_disabled) {
flags |= telegram_api::account_changeAuthorizationSettings::CALL_REQUESTS_DISABLED_MASK;
}
send_query(G()->net_query_creator().create(telegram_api::account_changeAuthorizationSettings(
flags, hash, encrypted_requests_disabled, call_requests_disabled)));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::account_changeAuthorizationSettings>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
bool result = result_ptr.move_as_ok();
LOG_IF(WARNING, !result) << "Failed to change session settings";
promise_.set_value(Unit());
}
void on_error(Status status) final {
promise_.set_error(std::move(status));
}
};
class SetAuthorizationTtlQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
public:
explicit SetAuthorizationTtlQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(int32 authorization_ttl_days) {
send_query(G()->net_query_creator().create(telegram_api::account_setAuthorizationTTL(authorization_ttl_days)));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::account_setAuthorizationTTL>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
bool result = result_ptr.move_as_ok();
LOG_IF(WARNING, !result) << "Failed to set inactive session TTL";
promise_.set_value(Unit());
}
void on_error(Status status) final {
promise_.set_error(std::move(status));
}
};
class GetWebAuthorizationsQuery final : public Td::ResultHandler { class GetWebAuthorizationsQuery final : public Td::ResultHandler {
Promise<td_api::object_ptr<td_api::connectedWebsites>> promise_; Promise<td_api::object_ptr<td_api::connectedWebsites>> promise_;
@ -356,6 +426,21 @@ void terminate_all_other_sessions(Td *td, Promise<Unit> &&promise) {
td->create_handler<ResetAuthorizationsQuery>(std::move(promise))->send(); td->create_handler<ResetAuthorizationsQuery>(std::move(promise))->send();
} }
void toggle_session_can_accept_calls(Td *td, int64 session_id, bool can_accept_calls, Promise<Unit> &&promise) {
td->create_handler<ChangeAuthorizationSettingsQuery>(std::move(promise))
->send(session_id, false, false, true, !can_accept_calls);
}
void toggle_session_can_accept_secret_chats(Td *td, int64 session_id, bool can_accept_secret_chats,
Promise<Unit> &&promise) {
td->create_handler<ChangeAuthorizationSettingsQuery>(std::move(promise))
->send(session_id, true, !can_accept_secret_chats, false, false);
}
void set_inactive_session_ttl_days(Td *td, int32 authorization_ttl_days, Promise<Unit> &&promise) {
td->create_handler<SetAuthorizationTtlQuery>(std::move(promise))->send(authorization_ttl_days);
}
void get_connected_websites(Td *td, Promise<td_api::object_ptr<td_api::connectedWebsites>> &&promise) { void get_connected_websites(Td *td, Promise<td_api::object_ptr<td_api::connectedWebsites>> &&promise) {
td->create_handler<GetWebAuthorizationsQuery>(std::move(promise))->send(); td->create_handler<GetWebAuthorizationsQuery>(std::move(promise))->send();
} }

View File

@ -28,6 +28,13 @@ void terminate_session(Td *td, int64 session_id, Promise<Unit> &&promise);
void terminate_all_other_sessions(Td *td, Promise<Unit> &&promise); void terminate_all_other_sessions(Td *td, Promise<Unit> &&promise);
void toggle_session_can_accept_calls(Td *td, int64 session_id, bool can_accept_calls, Promise<Unit> &&promise);
void toggle_session_can_accept_secret_chats(Td *td, int64 session_id, bool can_accept_secret_chats,
Promise<Unit> &&promise);
void set_inactive_session_ttl_days(Td *td, int32 authorization_ttl_days, Promise<Unit> &&promise);
void get_connected_websites(Td *td, Promise<td_api::object_ptr<td_api::connectedWebsites>> &&promise); void get_connected_websites(Td *td, Promise<td_api::object_ptr<td_api::connectedWebsites>> &&promise);
void disconnect_website(Td *td, int64 website_id, Promise<Unit> &&promise); void disconnect_website(Td *td, int64 website_id, Promise<Unit> &&promise);

View File

@ -672,8 +672,10 @@ void AuthManager::on_log_out_result(NetQueryPtr &result) {
if (result->is_ok()) { if (result->is_ok()) {
auto r_log_out = fetch_result<telegram_api::auth_logOut>(result->ok()); auto r_log_out = fetch_result<telegram_api::auth_logOut>(result->ok());
if (r_log_out.is_ok()) { if (r_log_out.is_ok()) {
if (!r_log_out.ok()) { auto logged_out = r_log_out.move_as_ok();
status = Status::Error(500, "auth.logOut returned false!"); if (!logged_out->future_auth_token_.empty()) {
G()->shared_config().set_option_string("authentication_token",
base64url_encode(logged_out->future_auth_token_.as_slice()));
} }
} else { } else {
status = r_log_out.move_as_error(); status = r_log_out.move_as_error();
@ -781,6 +783,9 @@ void AuthManager::on_get_authorization(tl_object_ptr<telegram_api::auth_Authoriz
if ((auth->flags_ & telegram_api::auth_authorization::TMP_SESSIONS_MASK) != 0) { if ((auth->flags_ & telegram_api::auth_authorization::TMP_SESSIONS_MASK) != 0) {
G()->shared_config().set_option_integer("session_count", auth->tmp_sessions_); G()->shared_config().set_option_integer("session_count", auth->tmp_sessions_);
} }
if (auth->setup_password_required_ && auth->otherwise_relogin_days_ > 0) {
G()->shared_config().set_option_integer("otherwise_relogin_days", auth->otherwise_relogin_days_);
}
td_->messages_manager_->on_authorization_success(); td_->messages_manager_->on_authorization_success();
td_->notification_manager_->init(); td_->notification_manager_->init();
td_->stickers_manager_->init(); td_->stickers_manager_->init();
@ -813,7 +818,8 @@ void AuthManager::on_result(NetQueryPtr result) {
type = net_query_type_; type = net_query_type_;
net_query_type_ = NetQueryType::None; net_query_type_ = NetQueryType::None;
if (result->is_error()) { if (result->is_error()) {
if ((type == NetQueryType::SignIn || type == NetQueryType::RequestQrCode || type == NetQueryType::ImportQrCode) && if ((type == NetQueryType::SendCode || type == NetQueryType::SignIn || type == NetQueryType::RequestQrCode ||
type == NetQueryType::ImportQrCode) &&
result->error().code() == 401 && result->error().message() == CSlice("SESSION_PASSWORD_NEEDED")) { result->error().code() == 401 && result->error().message() == CSlice("SESSION_PASSWORD_NEEDED")) {
auto dc_id = DcId::main(); auto dc_id = DcId::main();
if (type == NetQueryType::ImportQrCode) { if (type == NetQueryType::ImportQrCode) {

View File

@ -1086,17 +1086,17 @@ class ReportChannelSpamQuery final : public Td::ResultHandler {
explicit ReportChannelSpamQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) { explicit ReportChannelSpamQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
} }
void send(ChannelId channel_id, UserId user_id, const vector<MessageId> &message_ids) { void send(ChannelId channel_id, DialogId sender_dialog_id, const vector<MessageId> &message_ids) {
channel_id_ = channel_id; channel_id_ = channel_id;
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id); auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
CHECK(input_channel != nullptr); CHECK(input_channel != nullptr);
auto input_user = td_->contacts_manager_->get_input_user(user_id); auto input_peer = td_->messages_manager_->get_input_peer(sender_dialog_id, AccessRights::Know);
CHECK(input_user != nullptr); CHECK(input_peer != nullptr);
send_query(G()->net_query_creator().create(telegram_api::channels_reportSpam( send_query(G()->net_query_creator().create(telegram_api::channels_reportSpam(
std::move(input_channel), std::move(input_user), MessagesManager::get_server_message_ids(message_ids)))); std::move(input_channel), std::move(input_peer), MessagesManager::get_server_message_ids(message_ids))));
} }
void on_result(BufferSlice packet) final { void on_result(BufferSlice packet) final {
@ -1106,13 +1106,13 @@ class ReportChannelSpamQuery final : public Td::ResultHandler {
} }
bool result = result_ptr.move_as_ok(); bool result = result_ptr.move_as_ok();
LOG_IF(INFO, !result) << "Report spam has failed"; LOG_IF(INFO, !result) << "Report spam has failed in " << channel_id_;
promise_.set_value(Unit()); promise_.set_value(Unit());
} }
void on_error(Status status) final { void on_error(Status status) final {
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "ReportChannelSpamQuery"); // td_->contacts_manager_->on_get_channel_error(channel_id_, status, "ReportChannelSpamQuery");
promise_.set_error(std::move(status)); promise_.set_error(std::move(status));
} }
}; };
@ -1610,7 +1610,8 @@ class GetChatJoinRequestsQuery final : public Td::ResultHandler {
void send(DialogId dialog_id, const string &invite_link, const string &query, int32 offset_date, void send(DialogId dialog_id, const string &invite_link, const string &query, int32 offset_date,
UserId offset_user_id, int32 limit) { UserId offset_user_id, int32 limit) {
dialog_id_ = dialog_id; dialog_id_ = dialog_id;
is_full_list_ = invite_link.empty() && query.empty() && offset_date == 0 && !offset_user_id.is_valid() && limit >= 3; is_full_list_ =
invite_link.empty() && query.empty() && offset_date == 0 && !offset_user_id.is_valid() && limit >= 3;
auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write); auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
if (input_peer == nullptr) { if (input_peer == nullptr) {
@ -1687,7 +1688,7 @@ class HideChatJoinRequestQuery final : public Td::ResultHandler {
explicit HideChatJoinRequestQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) { explicit HideChatJoinRequestQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
} }
void send(DialogId dialog_id, UserId user_id, bool is_approved) { void send(DialogId dialog_id, UserId user_id, bool approve) {
dialog_id_ = dialog_id; dialog_id_ = dialog_id;
auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write); auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
if (input_peer == nullptr) { if (input_peer == nullptr) {
@ -1700,7 +1701,7 @@ class HideChatJoinRequestQuery final : public Td::ResultHandler {
} }
int32 flags = 0; int32 flags = 0;
if (is_approved) { if (approve) {
flags |= telegram_api::messages_hideChatJoinRequest::APPROVED_MASK; flags |= telegram_api::messages_hideChatJoinRequest::APPROVED_MASK;
} }
send_query(G()->net_query_creator().create(telegram_api::messages_hideChatJoinRequest( send_query(G()->net_query_creator().create(telegram_api::messages_hideChatJoinRequest(
@ -1724,6 +1725,49 @@ class HideChatJoinRequestQuery final : public Td::ResultHandler {
} }
}; };
class HideAllChatJoinRequestsQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
DialogId dialog_id_;
public:
explicit HideAllChatJoinRequestsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(DialogId dialog_id, const string &invite_link, bool approve) {
dialog_id_ = dialog_id;
auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
if (input_peer == nullptr) {
return on_error(Status::Error(400, "Can't access the chat"));
}
int32 flags = 0;
if (approve) {
flags |= telegram_api::messages_hideAllChatJoinRequests::APPROVED_MASK;
}
if (!invite_link.empty()) {
flags |= telegram_api::messages_hideAllChatJoinRequests::LINK_MASK;
}
send_query(G()->net_query_creator().create(
telegram_api::messages_hideAllChatJoinRequests(flags, false /*ignored*/, std::move(input_peer), invite_link)));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::messages_hideAllChatJoinRequests>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
auto result = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for HideAllChatJoinRequestsQuery: " << to_string(result);
td_->updates_manager_->on_get_updates(std::move(result), std::move(promise_));
}
void on_error(Status status) final {
td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "HideAllChatJoinRequestsQuery");
promise_.set_error(std::move(status));
}
};
class RevokeChatInviteLinkQuery final : public Td::ResultHandler { class RevokeChatInviteLinkQuery final : public Td::ResultHandler {
Promise<td_api::object_ptr<td_api::chatInviteLinks>> promise_; Promise<td_api::object_ptr<td_api::chatInviteLinks>> promise_;
DialogId dialog_id_; DialogId dialog_id_;
@ -2334,7 +2378,7 @@ class GetGroupsForDiscussionQuery final : public Td::ResultHandler {
} }
case telegram_api::messages_chatsSlice::ID: { case telegram_api::messages_chatsSlice::ID: {
auto chats = move_tl_object_as<telegram_api::messages_chatsSlice>(chats_ptr); auto chats = move_tl_object_as<telegram_api::messages_chatsSlice>(chats_ptr);
LOG(ERROR) << "Receive chatsSlice in result of GetCreatedPublicChannelsQuery"; LOG(ERROR) << "Receive chatsSlice in result of GetGroupsForDiscussionQuery";
td_->contacts_manager_->on_get_dialogs_for_discussion(std::move(chats->chats_)); td_->contacts_manager_->on_get_dialogs_for_discussion(std::move(chats->chats_));
break; break;
} }
@ -2425,8 +2469,11 @@ class GetFullUserQuery final : public Td::ResultHandler {
return on_error(result_ptr.move_as_error()); return on_error(result_ptr.move_as_error());
} }
LOG(DEBUG) << "Receive result for GetFullUserQuery: " << to_string(result_ptr.ok()); auto ptr = result_ptr.move_as_ok();
td_->contacts_manager_->on_get_user_full(result_ptr.move_as_ok()); LOG(DEBUG) << "Receive result for GetFullUserQuery: " << to_string(ptr);
td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetFullUserQuery");
td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetFullUserQuery");
td_->contacts_manager_->on_get_user_full(std::move(ptr->full_user_));
promise_.set_value(Unit()); promise_.set_value(Unit());
} }
@ -3591,6 +3638,7 @@ void ContactsManager::UserFull::store(StorerT &storer) const {
bool has_photo = !photo.is_empty(); bool has_photo = !photo.is_empty();
bool has_description = !description.empty(); bool has_description = !description.empty();
bool has_commands = !commands.empty(); bool has_commands = !commands.empty();
bool has_private_forward_name = !private_forward_name.empty();
BEGIN_STORE_FLAGS(); BEGIN_STORE_FLAGS();
STORE_FLAG(has_about); STORE_FLAG(has_about);
STORE_FLAG(is_blocked); STORE_FLAG(is_blocked);
@ -3602,6 +3650,7 @@ void ContactsManager::UserFull::store(StorerT &storer) const {
STORE_FLAG(supports_video_calls); STORE_FLAG(supports_video_calls);
STORE_FLAG(has_description); STORE_FLAG(has_description);
STORE_FLAG(has_commands); STORE_FLAG(has_commands);
STORE_FLAG(has_private_forward_name);
END_STORE_FLAGS(); END_STORE_FLAGS();
if (has_about) { if (has_about) {
store(about, storer); store(about, storer);
@ -3617,6 +3666,9 @@ void ContactsManager::UserFull::store(StorerT &storer) const {
if (has_commands) { if (has_commands) {
store(commands, storer); store(commands, storer);
} }
if (has_private_forward_name) {
store(private_forward_name, storer);
}
} }
template <class ParserT> template <class ParserT>
@ -3626,6 +3678,7 @@ void ContactsManager::UserFull::parse(ParserT &parser) {
bool has_photo; bool has_photo;
bool has_description; bool has_description;
bool has_commands; bool has_commands;
bool has_private_forward_name;
BEGIN_PARSE_FLAGS(); BEGIN_PARSE_FLAGS();
PARSE_FLAG(has_about); PARSE_FLAG(has_about);
PARSE_FLAG(is_blocked); PARSE_FLAG(is_blocked);
@ -3637,6 +3690,7 @@ void ContactsManager::UserFull::parse(ParserT &parser) {
PARSE_FLAG(supports_video_calls); PARSE_FLAG(supports_video_calls);
PARSE_FLAG(has_description); PARSE_FLAG(has_description);
PARSE_FLAG(has_commands); PARSE_FLAG(has_commands);
PARSE_FLAG(has_private_forward_name);
END_PARSE_FLAGS(); END_PARSE_FLAGS();
if (has_about) { if (has_about) {
parse(about, parser); parse(about, parser);
@ -3652,6 +3706,9 @@ void ContactsManager::UserFull::parse(ParserT &parser) {
if (has_commands) { if (has_commands) {
parse(commands, parser); parse(commands, parser);
} }
if (has_private_forward_name) {
parse(private_forward_name, parser);
}
} }
template <class StorerT> template <class StorerT>
@ -3675,6 +3732,7 @@ void ContactsManager::Chat::store(StorerT &storer) const {
STORE_FLAG(has_default_permissions_version); STORE_FLAG(has_default_permissions_version);
STORE_FLAG(has_pinned_message_version); STORE_FLAG(has_pinned_message_version);
STORE_FLAG(has_cache_version); STORE_FLAG(has_cache_version);
STORE_FLAG(noforwards);
END_STORE_FLAGS(); END_STORE_FLAGS();
store(title, storer); store(title, storer);
@ -3725,6 +3783,7 @@ void ContactsManager::Chat::parse(ParserT &parser) {
PARSE_FLAG(has_default_permissions_version); PARSE_FLAG(has_default_permissions_version);
PARSE_FLAG(has_pinned_message_version); PARSE_FLAG(has_pinned_message_version);
PARSE_FLAG(has_cache_version); PARSE_FLAG(has_cache_version);
PARSE_FLAG(noforwards);
END_PARSE_FLAGS(); END_PARSE_FLAGS();
parse(title, parser); parse(title, parser);
@ -3865,25 +3924,26 @@ void ContactsManager::Channel::store(StorerT &storer) const {
STORE_FLAG(false); STORE_FLAG(false);
STORE_FLAG(sign_messages); STORE_FLAG(sign_messages);
STORE_FLAG(false); STORE_FLAG(false);
STORE_FLAG(false); STORE_FLAG(false); // 5
STORE_FLAG(false); STORE_FLAG(false);
STORE_FLAG(is_megagroup); STORE_FLAG(is_megagroup);
STORE_FLAG(is_verified); STORE_FLAG(is_verified);
STORE_FLAG(has_photo); STORE_FLAG(has_photo);
STORE_FLAG(has_username); STORE_FLAG(has_username); // 10
STORE_FLAG(false); STORE_FLAG(false);
STORE_FLAG(use_new_rights); STORE_FLAG(use_new_rights);
STORE_FLAG(has_participant_count); STORE_FLAG(has_participant_count);
STORE_FLAG(have_default_permissions); STORE_FLAG(have_default_permissions);
STORE_FLAG(is_scam); STORE_FLAG(is_scam); // 15
STORE_FLAG(has_cache_version); STORE_FLAG(has_cache_version);
STORE_FLAG(has_linked_channel); STORE_FLAG(has_linked_channel);
STORE_FLAG(has_location); STORE_FLAG(has_location);
STORE_FLAG(is_slow_mode_enabled); STORE_FLAG(is_slow_mode_enabled);
STORE_FLAG(has_restriction_reasons); STORE_FLAG(has_restriction_reasons); // 20
STORE_FLAG(legacy_has_active_group_call); STORE_FLAG(legacy_has_active_group_call);
STORE_FLAG(is_fake); STORE_FLAG(is_fake);
STORE_FLAG(is_gigagroup); STORE_FLAG(is_gigagroup);
STORE_FLAG(noforwards);
END_STORE_FLAGS(); END_STORE_FLAGS();
store(status, storer); store(status, storer);
@ -3953,6 +4013,7 @@ void ContactsManager::Channel::parse(ParserT &parser) {
PARSE_FLAG(legacy_has_active_group_call); PARSE_FLAG(legacy_has_active_group_call);
PARSE_FLAG(is_fake); PARSE_FLAG(is_fake);
PARSE_FLAG(is_gigagroup); PARSE_FLAG(is_gigagroup);
PARSE_FLAG(noforwards);
END_PARSE_FLAGS(); END_PARSE_FLAGS();
if (use_new_rights) { if (use_new_rights) {
@ -4616,6 +4677,30 @@ RestrictedRights ContactsManager::get_secret_chat_default_permissions(SecretChat
return RestrictedRights(true, true, true, true, true, true, true, true, false, false, false); return RestrictedRights(true, true, true, true, true, true, true, true, false, false, false);
} }
bool ContactsManager::get_chat_has_protected_content(ChatId chat_id) const {
auto c = get_chat(chat_id);
if (c == nullptr) {
return false;
}
return c->noforwards;
}
bool ContactsManager::get_channel_has_protected_content(ChannelId channel_id) const {
auto c = get_channel(channel_id);
if (c == nullptr) {
return false;
}
return c->noforwards;
}
string ContactsManager::get_user_private_forward_name(UserId user_id) {
auto user_full = get_user_full_force(user_id);
if (user_full != nullptr) {
return user_full->private_forward_name;
}
return string();
}
string ContactsManager::get_dialog_about(DialogId dialog_id) { string ContactsManager::get_dialog_about(DialogId dialog_id) {
switch (dialog_id.get_type()) { switch (dialog_id.get_type()) {
case DialogType::User: { case DialogType::User: {
@ -6551,7 +6636,7 @@ void ContactsManager::send_load_async_graph_query(DcId dc_id, string token, int6
td_->create_handler<LoadAsyncGraphQuery>(std::move(promise))->send(token, x, dc_id); td_->create_handler<LoadAsyncGraphQuery>(std::move(promise))->send(token, x, dc_id);
} }
void ContactsManager::report_channel_spam(ChannelId channel_id, UserId user_id, const vector<MessageId> &message_ids, void ContactsManager::report_channel_spam(ChannelId channel_id, const vector<MessageId> &message_ids,
Promise<Unit> &&promise) { Promise<Unit> &&promise) {
auto c = get_channel(channel_id); auto c = get_channel(channel_id);
if (c == nullptr) { if (c == nullptr) {
@ -6561,17 +6646,11 @@ void ContactsManager::report_channel_spam(ChannelId channel_id, UserId user_id,
return promise.set_error(Status::Error(400, "Spam can be reported only in supergroups")); return promise.set_error(Status::Error(400, "Spam can be reported only in supergroups"));
} }
if (!have_input_user(user_id)) {
return promise.set_error(Status::Error(400, "Have no access to the user"));
}
if (user_id == get_my_id()) {
return promise.set_error(Status::Error(400, "Can't report self"));
}
if (message_ids.empty()) { if (message_ids.empty()) {
return promise.set_error(Status::Error(400, "Message list is empty")); return promise.set_error(Status::Error(400, "Message list is empty"));
} }
DialogId sender_dialog_id;
vector<MessageId> server_message_ids; vector<MessageId> server_message_ids;
for (auto &message_id : message_ids) { for (auto &message_id : message_ids) {
if (message_id.is_valid_scheduled()) { if (message_id.is_valid_scheduled()) {
@ -6582,15 +6661,38 @@ void ContactsManager::report_channel_spam(ChannelId channel_id, UserId user_id,
return promise.set_error(Status::Error(400, "Message not found")); return promise.set_error(Status::Error(400, "Message not found"));
} }
if (message_id.is_server()) { if (!message_id.is_server()) {
server_message_ids.push_back(message_id); continue;
} }
auto current_sender_dialog_id = td_->messages_manager_->get_message_sender({DialogId(channel_id), message_id});
if (!current_sender_dialog_id.is_valid()) {
continue;
}
if (sender_dialog_id.is_valid()) {
if (current_sender_dialog_id != sender_dialog_id) {
return promise.set_error(Status::Error(400, "All messages nust be from the same sender"));
}
} else {
sender_dialog_id = current_sender_dialog_id;
}
server_message_ids.push_back(message_id);
} }
if (server_message_ids.empty()) { if (server_message_ids.empty()) {
return promise.set_value(Unit()); return promise.set_value(Unit());
} }
CHECK(sender_dialog_id.is_valid());
td_->create_handler<ReportChannelSpamQuery>(std::move(promise))->send(channel_id, user_id, server_message_ids); if (!td_->messages_manager_->have_input_peer(sender_dialog_id, AccessRights::Know)) {
return promise.set_error(Status::Error(400, "Have no access to the user"));
}
if (sender_dialog_id == DialogId(get_my_id())) {
return promise.set_error(Status::Error(400, "Can't report self"));
}
td_->create_handler<ReportChannelSpamQuery>(std::move(promise))
->send(channel_id, sender_dialog_id, server_message_ids);
} }
void ContactsManager::delete_chat(ChatId chat_id, Promise<Unit> &&promise) { void ContactsManager::delete_chat(ChatId chat_id, Promise<Unit> &&promise) {
@ -6750,16 +6852,25 @@ void ContactsManager::set_channel_participant_status(ChannelId channel_id, Dialo
return promise.set_error(Status::Error(400, "Chat info not found")); return promise.set_error(Status::Error(400, "Chat info not found"));
} }
auto input_peer = td_->messages_manager_->get_input_peer(participant_dialog_id, AccessRights::Read);
if (input_peer == nullptr) {
return promise.set_error(Status::Error(400, "Member not found"));
}
if (participant_dialog_id == DialogId(get_my_id())) { if (participant_dialog_id == DialogId(get_my_id())) {
// fast path is needed, because get_channel_status may return Creator, while GetChannelParticipantQuery returning Left // fast path is needed, because get_channel_status may return Creator, while GetChannelParticipantQuery returning Left
return set_channel_participant_status_impl(channel_id, participant_dialog_id, std::move(status), return set_channel_participant_status_impl(channel_id, participant_dialog_id, std::move(status),
get_channel_status(c), std::move(promise)); get_channel_status(c), std::move(promise));
} }
if (participant_dialog_id.get_type() != DialogType::User) {
if (status.is_administrator() || status.is_member() || status.is_restricted()) {
return promise.set_error(Status::Error(400, "Other chats can be only banned or unbanned"));
}
// always pretend that old_status is different
return restrict_channel_participant(
channel_id, participant_dialog_id, std::move(status),
status.is_banned() ? DialogParticipantStatus::Left() : DialogParticipantStatus::Banned(0), std::move(promise));
}
auto input_peer = td_->messages_manager_->get_input_peer(participant_dialog_id, AccessRights::Read);
if (input_peer == nullptr) {
return promise.set_error(Status::Error(400, "Member not found"));
}
auto on_result_promise = auto on_result_promise =
PromiseCreator::lambda([actor_id = actor_id(this), channel_id, participant_dialog_id, status, PromiseCreator::lambda([actor_id = actor_id(this), channel_id, participant_dialog_id, status,
@ -7240,10 +7351,16 @@ void ContactsManager::get_dialog_join_requests(DialogId dialog_id, const string
->send(dialog_id, invite_link, query, offset_date, offset_user_id, limit); ->send(dialog_id, invite_link, query, offset_date, offset_user_id, limit);
} }
void ContactsManager::process_dialog_join_requests(DialogId dialog_id, UserId user_id, bool is_approved, void ContactsManager::process_dialog_join_request(DialogId dialog_id, UserId user_id, bool approve,
Promise<Unit> &&promise) { Promise<Unit> &&promise) {
TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id)); TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id));
td_->create_handler<HideChatJoinRequestQuery>(std::move(promise))->send(dialog_id, user_id, is_approved); td_->create_handler<HideChatJoinRequestQuery>(std::move(promise))->send(dialog_id, user_id, approve);
}
void ContactsManager::process_dialog_join_requests(DialogId dialog_id, const string &invite_link, bool approve,
Promise<Unit> &&promise) {
TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id));
td_->create_handler<HideAllChatJoinRequestsQuery>(std::move(promise))->send(dialog_id, invite_link, approve);
} }
void ContactsManager::revoke_dialog_invite_link(DialogId dialog_id, const string &invite_link, void ContactsManager::revoke_dialog_invite_link(DialogId dialog_id, const string &invite_link,
@ -7376,7 +7493,7 @@ void ContactsManager::restrict_channel_participant(ChannelId channel_id, DialogI
return promise.set_error(Status::Error(400, "Not in the chat")); return promise.set_error(Status::Error(400, "Not in the chat"));
} }
} }
auto input_peer = td_->messages_manager_->get_input_peer(participant_dialog_id, AccessRights::Read); auto input_peer = td_->messages_manager_->get_input_peer(participant_dialog_id, AccessRights::Know);
if (input_peer == nullptr) { if (input_peer == nullptr) {
return promise.set_error(Status::Error(400, "Member not found")); return promise.set_error(Status::Error(400, "Member not found"));
} }
@ -7400,7 +7517,7 @@ void ContactsManager::restrict_channel_participant(ChannelId channel_id, DialogI
// ok; // ok;
break; break;
case DialogType::Channel: case DialogType::Channel:
if (!status.is_banned() && !status.is_left()) { if (status.is_administrator() || status.is_member() || status.is_restricted()) {
return promise.set_error(Status::Error(400, "Other chats can be only banned or unbanned")); return promise.set_error(Status::Error(400, "Other chats can be only banned or unbanned"));
} }
break; break;
@ -7475,10 +7592,12 @@ vector<ChannelId> ContactsManager::get_channel_ids(vector<tl_object_ptr<telegram
auto channel_id = get_channel_id(chat); auto channel_id = get_channel_id(chat);
if (!channel_id.is_valid()) { if (!channel_id.is_valid()) {
LOG(ERROR) << "Receive invalid " << channel_id << " from " << source << " in " << to_string(chat); LOG(ERROR) << "Receive invalid " << channel_id << " from " << source << " in " << to_string(chat);
} else { continue;
channel_ids.push_back(channel_id);
} }
on_get_chat(std::move(chat), source); on_get_chat(std::move(chat), source);
if (have_channel(channel_id)) {
channel_ids.push_back(channel_id);
}
} }
return channel_ids; return channel_ids;
} }
@ -7503,26 +7622,184 @@ vector<DialogId> ContactsManager::get_dialog_ids(vector<tl_object_ptr<telegram_a
return dialog_ids; return dialog_ids;
} }
vector<DialogId> ContactsManager::get_created_public_dialogs(PublicDialogType type, Promise<Unit> &&promise) { void ContactsManager::return_created_public_dialogs(Promise<td_api::object_ptr<td_api::chats>> &&promise,
auto index = static_cast<int32>(type); const vector<ChannelId> &channel_ids) {
if (created_public_channels_inited_[index]) { if (!promise) {
promise.set_value(Unit()); return;
return transform(created_public_channels_[index], [&](ChannelId channel_id) {
DialogId dialog_id(channel_id);
td_->messages_manager_->force_create_dialog(dialog_id, "get_created_public_dialogs");
return dialog_id;
});
} }
td_->create_handler<GetCreatedPublicChannelsQuery>(std::move(promise))->send(type, false); auto total_count = narrow_cast<int32>(channel_ids.size());
return {}; promise.set_value(td_api::make_object<td_api::chats>(
total_count, transform(channel_ids, [](ChannelId channel_id) { return DialogId(channel_id).get(); })));
}
void ContactsManager::get_created_public_dialogs(PublicDialogType type,
Promise<td_api::object_ptr<td_api::chats>> &&promise,
bool from_binlog) {
auto index = static_cast<int32>(type);
if (created_public_channels_inited_[index]) {
return return_created_public_dialogs(std::move(promise), created_public_channels_[index]);
}
if (get_created_public_channels_queries_[index].empty() && G()->parameters().use_chat_info_db) {
auto pmc_key = PSTRING() << "public_channels" << index;
auto str = G()->td_db()->get_binlog_pmc()->get(pmc_key);
if (!str.empty()) {
auto r_channel_ids = transform(full_split(Slice(str), ','), [](Slice str) -> Result<ChannelId> {
TRY_RESULT(channel_id_int, to_integer_safe<int64>(str));
ChannelId channel_id(channel_id_int);
if (!channel_id.is_valid()) {
return Status::Error("Have invalid channel ID");
}
return channel_id;
});
if (std::any_of(r_channel_ids.begin(), r_channel_ids.end(),
[](auto &r_channel_id) { return r_channel_id.is_error(); })) {
LOG(ERROR) << "Can't parse " << str;
G()->td_db()->get_binlog_pmc()->erase(pmc_key);
} else {
Dependencies dependencies;
vector<ChannelId> channel_ids;
for (auto &r_channel_id : r_channel_ids) {
auto channel_id = r_channel_id.move_as_ok();
add_dialog_and_dependencies(dependencies, DialogId(channel_id));
channel_ids.push_back(channel_id);
}
if (!resolve_dependencies_force(td_, dependencies, "get_created_public_dialogs")) {
G()->td_db()->get_binlog_pmc()->erase(pmc_key);
} else {
created_public_channels_[index] = std::move(channel_ids);
created_public_channels_inited_[index] = true;
if (type == PublicDialogType::HasUsername) {
update_created_public_broadcasts();
}
if (from_binlog) {
return return_created_public_dialogs(std::move(promise), created_public_channels_[index]);
}
}
}
}
}
reload_created_public_dialogs(type, std::move(promise));
}
void ContactsManager::reload_created_public_dialogs(PublicDialogType type,
Promise<td_api::object_ptr<td_api::chats>> &&promise) {
auto index = static_cast<int32>(type);
get_created_public_channels_queries_[index].push_back(std::move(promise));
if (get_created_public_channels_queries_[index].size() == 1) {
auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), type](Result<Unit> &&result) {
send_closure(actor_id, &ContactsManager::finish_get_created_public_dialogs, type, std::move(result));
});
td_->create_handler<GetCreatedPublicChannelsQuery>(std::move(query_promise))->send(type, false);
}
}
void ContactsManager::finish_get_created_public_dialogs(PublicDialogType type, Result<Unit> &&result) {
auto index = static_cast<int32>(type);
auto promises = std::move(get_created_public_channels_queries_[index]);
reset_to_empty(get_created_public_channels_queries_[index]);
if (G()->close_flag()) {
result = G()->close_status();
}
if (result.is_error()) {
for (auto &promise : promises) {
promise.set_error(result.error().clone());
}
return;
}
CHECK(created_public_channels_inited_[index]);
for (auto &promise : promises) {
return_created_public_dialogs(std::move(promise), created_public_channels_[index]);
}
}
void ContactsManager::update_created_public_channels(Channel *c, ChannelId channel_id) {
if (created_public_channels_inited_[0]) {
bool was_changed = false;
if (c->username.empty() || !c->status.is_creator()) {
was_changed = td::remove(created_public_channels_[0], channel_id);
} else {
if (!td::contains(created_public_channels_[0], channel_id)) {
created_public_channels_[0].push_back(channel_id);
was_changed = true;
}
}
if (was_changed) {
if (!c->is_megagroup) {
update_created_public_broadcasts();
}
save_created_public_channels(PublicDialogType::HasUsername);
reload_created_public_dialogs(PublicDialogType::HasUsername, Promise<td_api::object_ptr<td_api::chats>>());
}
}
if (created_public_channels_inited_[1]) {
bool was_changed = false;
if (!c->has_location || !c->status.is_creator()) {
was_changed = td::remove(created_public_channels_[1], channel_id);
} else {
if (!td::contains(created_public_channels_[1], channel_id)) {
created_public_channels_[1].push_back(channel_id);
was_changed = true;
}
}
if (was_changed) {
save_created_public_channels(PublicDialogType::IsLocationBased);
reload_created_public_dialogs(PublicDialogType::IsLocationBased, Promise<td_api::object_ptr<td_api::chats>>());
}
}
} }
void ContactsManager::on_get_created_public_channels(PublicDialogType type, void ContactsManager::on_get_created_public_channels(PublicDialogType type,
vector<tl_object_ptr<telegram_api::Chat>> &&chats) { vector<tl_object_ptr<telegram_api::Chat>> &&chats) {
auto index = static_cast<int32>(type); auto index = static_cast<int32>(type);
created_public_channels_[index] = get_channel_ids(std::move(chats), "on_get_created_public_channels"); auto channel_ids = get_channel_ids(std::move(chats), "on_get_created_public_channels");
if (created_public_channels_inited_[index] && created_public_channels_[index] == channel_ids) {
return;
}
for (auto channel_id : channel_ids) {
td_->messages_manager_->force_create_dialog(DialogId(channel_id), "on_get_created_public_channels");
}
created_public_channels_[index] = std::move(channel_ids);
created_public_channels_inited_[index] = true; created_public_channels_inited_[index] = true;
if (type == PublicDialogType::HasUsername) {
update_created_public_broadcasts();
}
save_created_public_channels(type);
}
void ContactsManager::save_created_public_channels(PublicDialogType type) {
auto index = static_cast<int32>(type);
CHECK(created_public_channels_inited_[index]);
if (G()->parameters().use_chat_info_db) {
G()->td_db()->get_binlog_pmc()->set(
PSTRING() << "public_channels" << index,
implode(
transform(created_public_channels_[index], [](auto channel_id) { return PSTRING() << channel_id.get(); }),
','));
}
}
void ContactsManager::update_created_public_broadcasts() {
CHECK(created_public_channels_inited_[0]);
vector<ChannelId> channel_ids;
for (auto &channel_id : created_public_channels_[0]) {
auto c = get_channel(channel_id);
if (!c->is_megagroup) {
channel_ids.push_back(channel_id);
}
}
send_closure_later(G()->messages_manager(), &MessagesManager::on_update_created_public_broadcasts,
std::move(channel_ids));
} }
void ContactsManager::check_created_public_dialogs_limit(PublicDialogType type, Promise<Unit> &&promise) { void ContactsManager::check_created_public_dialogs_limit(PublicDialogType type, Promise<Unit> &&promise) {
@ -7896,12 +8173,16 @@ void ContactsManager::on_update_phone_number_privacy() {
void ContactsManager::invalidate_user_full(UserId user_id) { void ContactsManager::invalidate_user_full(UserId user_id) {
auto user_full = get_user_full_force(user_id); auto user_full = get_user_full_force(user_id);
if (user_full != nullptr && !user_full->is_expired()) { if (user_full != nullptr) {
td_->messages_manager_->on_dialog_info_full_invalidated(DialogId(user_id));
if (!user_full->is_expired()) {
user_full->expires_at = 0.0; user_full->expires_at = 0.0;
user_full->need_save_to_database = true; user_full->need_save_to_database = true;
update_user_full(user_full, user_id, "invalidate_user_full"); update_user_full(user_full, user_id, "invalidate_user_full");
} }
}
} }
UserId ContactsManager::get_user_id(const tl_object_ptr<telegram_api::User> &user) { UserId ContactsManager::get_user_id(const tl_object_ptr<telegram_api::User> &user) {
@ -9491,7 +9772,7 @@ void ContactsManager::on_load_channel_full_from_database(ChannelId channel_id, s
if (invalidated_channels_full_.erase(channel_id) > 0 || if (invalidated_channels_full_.erase(channel_id) > 0 ||
(!c->is_slow_mode_enabled && channel_full->slow_mode_delay != 0)) { (!c->is_slow_mode_enabled && channel_full->slow_mode_delay != 0)) {
do_invalidate_channel_full(channel_full, !c->is_slow_mode_enabled); do_invalidate_channel_full(channel_full, channel_id, !c->is_slow_mode_enabled);
} }
td_->group_call_manager_->on_update_dialog_about(DialogId(channel_id), channel_full->description, false); td_->group_call_manager_->on_update_dialog_about(DialogId(channel_id), channel_full->description, false);
@ -9659,7 +9940,7 @@ void ContactsManager::update_chat(Chat *c, ChatId chat_id, bool from_binlog, boo
c->is_title_changed = false; c->is_title_changed = false;
} }
if (c->is_default_permissions_changed) { if (c->is_default_permissions_changed) {
td_->messages_manager_->on_dialog_permissions_updated(DialogId(chat_id)); td_->messages_manager_->on_dialog_default_permissions_updated(DialogId(chat_id));
c->is_default_permissions_changed = false; c->is_default_permissions_changed = false;
} }
if (c->is_is_active_changed) { if (c->is_is_active_changed) {
@ -9672,6 +9953,10 @@ void ContactsManager::update_chat(Chat *c, ChatId chat_id, bool from_binlog, boo
} }
c->is_status_changed = false; c->is_status_changed = false;
} }
if (c->is_noforwards_changed) {
td_->messages_manager_->on_dialog_has_protected_content_updated(DialogId(chat_id));
c->is_noforwards_changed = false;
}
LOG(DEBUG) << "Update " << chat_id << ": need_save_to_database = " << c->need_save_to_database LOG(DEBUG) << "Update " << chat_id << ": need_save_to_database = " << c->need_save_to_database
<< ", is_changed = " << c->is_changed; << ", is_changed = " << c->is_changed;
@ -9739,25 +10024,34 @@ void ContactsManager::update_channel(Channel *c, ChannelId channel_id, bool from
c->is_status_changed = false; c->is_status_changed = false;
} }
if (c->is_username_changed) { if (c->is_username_changed) {
if (c->status.is_creator() && created_public_channels_inited_[0]) { if (c->status.is_creator()) {
if (c->username.empty()) { update_created_public_channels(c, channel_id);
td::remove(created_public_channels_[0], channel_id);
} else {
if (!td::contains(created_public_channels_[0], channel_id)) {
created_public_channels_[0].push_back(channel_id);
}
}
} }
c->is_username_changed = false; c->is_username_changed = false;
} }
if (c->is_default_permissions_changed) { if (c->is_default_permissions_changed) {
td_->messages_manager_->on_dialog_permissions_updated(DialogId(channel_id)); td_->messages_manager_->on_dialog_default_permissions_updated(DialogId(channel_id));
if (c->default_permissions != if (c->default_permissions !=
RestrictedRights(false, false, false, false, false, false, false, false, false, false, false)) { RestrictedRights(false, false, false, false, false, false, false, false, false, false, false)) {
remove_dialog_suggested_action(SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)}); remove_dialog_suggested_action(SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)});
} }
c->is_default_permissions_changed = false; c->is_default_permissions_changed = false;
} }
if (c->is_has_location_changed) {
if (c->status.is_creator()) {
update_created_public_channels(c, channel_id);
}
c->is_has_location_changed = false;
}
if (c->is_creator_changed) {
update_created_public_channels(c, channel_id);
c->is_creator_changed = false;
}
if (c->is_noforwards_changed) {
td_->messages_manager_->on_dialog_has_protected_content_updated(DialogId(channel_id));
c->is_noforwards_changed = false;
}
if (!td_->auth_manager_->is_bot()) { if (!td_->auth_manager_->is_bot()) {
if (c->restriction_reasons.empty()) { if (c->restriction_reasons.empty()) {
restricted_channel_ids_.erase(channel_id); restricted_channel_ids_.erase(channel_id);
@ -10008,15 +10302,10 @@ void ContactsManager::on_get_users(vector<tl_object_ptr<telegram_api::User>> &&u
} }
void ContactsManager::on_get_user_full(tl_object_ptr<telegram_api::userFull> &&user) { void ContactsManager::on_get_user_full(tl_object_ptr<telegram_api::userFull> &&user) {
UserId user_id = get_user_id(user->user_); UserId user_id(user->id_);
if (!user_id.is_valid()) {
LOG(ERROR) << "Receive invalid " << user_id;
return;
}
on_get_user(std::move(user->user_), "on_get_user_full");
User *u = get_user(user_id); User *u = get_user(user_id);
if (u == nullptr) { if (u == nullptr) {
LOG(ERROR) << "Failed to find " << user_id;
return; return;
} }
@ -10072,10 +10361,12 @@ void ContactsManager::on_get_user_full(tl_object_ptr<telegram_api::userFull> &&u
bool supports_video_calls = user->video_calls_available_ && !user->phone_calls_private_; bool supports_video_calls = user->video_calls_available_ && !user->phone_calls_private_;
bool has_private_calls = user->phone_calls_private_; bool has_private_calls = user->phone_calls_private_;
if (user_full->can_be_called != can_be_called || user_full->supports_video_calls != supports_video_calls || if (user_full->can_be_called != can_be_called || user_full->supports_video_calls != supports_video_calls ||
user_full->has_private_calls != has_private_calls) { user_full->has_private_calls != has_private_calls ||
user_full->private_forward_name != user->private_forward_name_) {
user_full->can_be_called = can_be_called; user_full->can_be_called = can_be_called;
user_full->supports_video_calls = supports_video_calls; user_full->supports_video_calls = supports_video_calls;
user_full->has_private_calls = has_private_calls; user_full->has_private_calls = has_private_calls;
user_full->private_forward_name = std::move(user->private_forward_name_);
user_full->is_changed = true; user_full->is_changed = true;
} }
@ -10538,6 +10829,15 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
&MessagesManager::on_update_dialog_default_join_group_call_as_dialog_id, DialogId(channel_id), &MessagesManager::on_update_dialog_default_join_group_call_as_dialog_id, DialogId(channel_id),
default_join_group_call_as_dialog_id, false); default_join_group_call_as_dialog_id, false);
} }
{
DialogId default_send_message_as_dialog_id;
if (channel->default_send_as_ != nullptr) {
default_send_message_as_dialog_id = DialogId(channel->default_send_as_);
}
// use send closure later to not create synchronously default_send_message_as_dialog_id
send_closure_later(G()->messages_manager(), &MessagesManager::on_update_dialog_default_send_message_as_dialog_id,
DialogId(channel_id), default_send_message_as_dialog_id, false);
}
if (participant_count >= 190) { if (participant_count >= 190) {
int32 online_member_count = 0; int32 online_member_count = 0;
@ -11295,6 +11595,7 @@ void ContactsManager::drop_user_full(UserId user_id) {
user_full->description = string(); user_full->description = string();
user_full->commands.clear(); user_full->commands.clear();
user_full->common_chat_count = 0; user_full->common_chat_count = 0;
user_full->private_forward_name.clear();
user_full->is_changed = true; user_full->is_changed = true;
update_user_full(user_full, user_id, "drop_user_full"); update_user_full(user_full, user_id, "drop_user_full");
@ -11550,16 +11851,14 @@ bool ContactsManager::on_get_channel_error(ChannelId channel_id, const Status &s
if (!c->username.empty()) { if (!c->username.empty()) {
LOG(INFO) << "Drop username of " << channel_id; LOG(INFO) << "Drop username of " << channel_id;
on_update_channel_username(c, channel_id, ""); on_update_channel_username(c, channel_id, "");
update_channel(c, channel_id);
} }
if (c->has_location) { on_update_channel_has_location(c, channel_id, false);
LOG(INFO) << "Drop location of " << channel_id;
c->has_location = false;
update_channel(c, channel_id);
}
on_update_channel_linked_channel_id(channel_id, ChannelId()); on_update_channel_linked_channel_id(channel_id, ChannelId());
update_channel(c, channel_id);
remove_dialog_access_by_invite_link(DialogId(channel_id)); remove_dialog_access_by_invite_link(DialogId(channel_id));
} }
invalidate_channel_full(channel_id, !c->is_slow_mode_enabled); invalidate_channel_full(channel_id, !c->is_slow_mode_enabled);
@ -12046,15 +12345,17 @@ void ContactsManager::invalidate_channel_full(ChannelId channel_id, bool need_dr
LOG(INFO) << "Invalidate supergroup full for " << channel_id; LOG(INFO) << "Invalidate supergroup full for " << channel_id;
auto channel_full = get_channel_full(channel_id, true, "invalidate_channel_full"); // must not load ChannelFull auto channel_full = get_channel_full(channel_id, true, "invalidate_channel_full"); // must not load ChannelFull
if (channel_full != nullptr) { if (channel_full != nullptr) {
do_invalidate_channel_full(channel_full, need_drop_slow_mode_delay); do_invalidate_channel_full(channel_full, channel_id, need_drop_slow_mode_delay);
update_channel_full(channel_full, channel_id, "invalidate_channel_full"); update_channel_full(channel_full, channel_id, "invalidate_channel_full");
} else { } else {
invalidated_channels_full_.insert(channel_id); invalidated_channels_full_.insert(channel_id);
} }
} }
void ContactsManager::do_invalidate_channel_full(ChannelFull *channel_full, bool need_drop_slow_mode_delay) { void ContactsManager::do_invalidate_channel_full(ChannelFull *channel_full, ChannelId channel_id,
bool need_drop_slow_mode_delay) {
CHECK(channel_full != nullptr); CHECK(channel_full != nullptr);
td_->messages_manager_->on_dialog_info_full_invalidated(DialogId(channel_id));
if (channel_full->expires_at >= Time::now()) { if (channel_full->expires_at >= Time::now()) {
channel_full->expires_at = 0.0; channel_full->expires_at = 0.0;
channel_full->need_save_to_database = true; channel_full->need_save_to_database = true;
@ -12310,11 +12611,8 @@ void ContactsManager::on_update_channel_full_location(ChannelFull *channel_full,
Channel *c = get_channel(channel_id); Channel *c = get_channel(channel_id);
CHECK(c != nullptr); CHECK(c != nullptr);
if (location.empty() == c->has_location) { on_update_channel_has_location(c, channel_id, !location.empty());
c->has_location = !location.empty();
c->is_changed = true;
update_channel(c, channel_id); update_channel(c, channel_id);
}
} }
void ContactsManager::on_update_channel_full_slow_mode_delay(ChannelFull *channel_full, ChannelId channel_id, void ContactsManager::on_update_channel_full_slow_mode_delay(ChannelFull *channel_full, ChannelId channel_id,
@ -12802,6 +13100,15 @@ void ContactsManager::on_update_chat_default_permissions(Chat *c, ChatId chat_id
} }
} }
void ContactsManager::on_update_chat_noforwards(Chat *c, ChatId chat_id, bool noforwards) {
if (c->noforwards != noforwards) {
LOG(INFO) << "Update " << chat_id << " has_protected_content from " << c->noforwards << " to " << noforwards;
c->noforwards = noforwards;
c->is_noforwards_changed = true;
c->need_save_to_database = true;
}
}
void ContactsManager::on_update_chat_pinned_message(ChatId chat_id, MessageId pinned_message_id, int32 version) { void ContactsManager::on_update_chat_pinned_message(ChatId chat_id, MessageId pinned_message_id, int32 version) {
if (!chat_id.is_valid()) { if (!chat_id.is_valid()) {
LOG(ERROR) << "Receive invalid " << chat_id; LOG(ERROR) << "Receive invalid " << chat_id;
@ -13059,7 +13366,7 @@ void ContactsManager::on_update_channel_status(Channel *c, ChannelId channel_id,
} }
} }
void ContactsManager::on_channel_status_changed(const Channel *c, ChannelId channel_id, void ContactsManager::on_channel_status_changed(Channel *c, ChannelId channel_id,
const DialogParticipantStatus &old_status, const DialogParticipantStatus &old_status,
const DialogParticipantStatus &new_status) { const DialogParticipantStatus &new_status) {
CHECK(c->is_update_supergroup_sent); CHECK(c->is_update_supergroup_sent);
@ -13070,7 +13377,7 @@ void ContactsManager::on_channel_status_changed(const Channel *c, ChannelId chan
auto channel_full = get_channel_full(channel_id, true, "on_channel_status_changed"); auto channel_full = get_channel_full(channel_id, true, "on_channel_status_changed");
if (channel_full != nullptr) { // otherwise invite_link will be dropped when the channel is loaded if (channel_full != nullptr) { // otherwise invite_link will be dropped when the channel is loaded
on_update_channel_full_invite_link(channel_full, nullptr); on_update_channel_full_invite_link(channel_full, nullptr);
do_invalidate_channel_full(channel_full, !c->is_slow_mode_enabled); do_invalidate_channel_full(channel_full, channel_id, !c->is_slow_mode_enabled);
update_channel_full(channel_full, channel_id, "on_channel_status_changed"); update_channel_full(channel_full, channel_id, "on_channel_status_changed");
} }
} else { } else {
@ -13078,10 +13385,7 @@ void ContactsManager::on_channel_status_changed(const Channel *c, ChannelId chan
} }
if (old_status.is_creator() != new_status.is_creator()) { if (old_status.is_creator() != new_status.is_creator()) {
for (size_t i = 0; i < 2; i++) { c->is_creator_changed = true;
created_public_channels_inited_[i] = false;
created_public_channels_[i].clear();
}
send_get_channel_full_query(nullptr, channel_id, Auto(), "update channel owner"); send_get_channel_full_query(nullptr, channel_id, Auto(), "update channel owner");
reload_dialog_administrators(DialogId(channel_id), 0, Auto()); reload_dialog_administrators(DialogId(channel_id), 0, Auto());
@ -13123,6 +13427,24 @@ void ContactsManager::on_update_channel_default_permissions(Channel *c, ChannelI
} }
} }
void ContactsManager::on_update_channel_has_location(Channel *c, ChannelId channel_id, bool has_location) {
if (c->has_location != has_location) {
LOG(INFO) << "Update " << channel_id << " has_location from " << c->has_location << " to " << has_location;
c->has_location = has_location;
c->is_has_location_changed = true;
c->is_changed = true;
}
}
void ContactsManager::on_update_channel_noforwards(Channel *c, ChannelId channel_id, bool noforwards) {
if (c->noforwards != noforwards) {
LOG(INFO) << "Update " << channel_id << " has_protected_content from " << c->noforwards << " to " << noforwards;
c->noforwards = noforwards;
c->is_noforwards_changed = true;
c->need_save_to_database = true;
}
}
void ContactsManager::on_update_channel_username(ChannelId channel_id, string &&username) { void ContactsManager::on_update_channel_username(ChannelId channel_id, string &&username) {
if (!channel_id.is_valid()) { if (!channel_id.is_valid()) {
LOG(ERROR) << "Receive invalid " << channel_id; LOG(ERROR) << "Receive invalid " << channel_id;
@ -14027,7 +14349,7 @@ void ContactsManager::send_get_chat_full_query(ChatId chat_id, Promise<Unit> &&p
} }
}); });
get_chat_full_queries_.add_query(chat_id.get(), std::move(send_query), std::move(promise)); get_chat_full_queries_.add_query(DialogId(chat_id).get(), std::move(send_query), std::move(promise));
} }
int32 ContactsManager::get_chat_participant_count(ChatId chat_id) const { int32 ContactsManager::get_chat_participant_count(ChatId chat_id) const {
@ -14372,7 +14694,7 @@ void ContactsManager::send_get_channel_full_query(ChannelFull *channel_full, Cha
td->create_handler<GetFullChannelQuery>(promise.move_as_ok())->send(channel_id, std::move(input_channel)); td->create_handler<GetFullChannelQuery>(promise.move_as_ok())->send(channel_id, std::move(input_channel));
} }
}); });
get_channel_full_queries_.add_query(channel_id.get(), std::move(send_query), std::move(promise)); get_chat_full_queries_.add_query(DialogId(channel_id).get(), std::move(send_query), std::move(promise));
} }
bool ContactsManager::have_secret_chat(SecretChatId secret_chat_id) const { bool ContactsManager::have_secret_chat(SecretChatId secret_chat_id) const {
@ -15170,6 +15492,7 @@ void ContactsManager::on_chat_update(telegram_api::chat &chat, const char *sourc
chat.version_); chat.version_);
on_update_chat_photo(c, chat_id, std::move(chat.photo_)); on_update_chat_photo(c, chat_id, std::move(chat.photo_));
on_update_chat_active(c, chat_id, is_active); on_update_chat_active(c, chat_id, is_active);
on_update_chat_noforwards(c, chat_id, chat.noforwards_);
on_update_chat_migrated_to_channel_id(c, chat_id, migrated_to_channel_id); on_update_chat_migrated_to_channel_id(c, chat_id, migrated_to_channel_id);
LOG_IF(INFO, !is_active && !migrated_to_channel_id.is_valid()) << chat_id << " is deactivated" << debug_str; LOG_IF(INFO, !is_active && !migrated_to_channel_id.is_valid()) << chat_id << " is deactivated" << debug_str;
if (c->cache_version != Chat::CACHE_VERSION) { if (c->cache_version != Chat::CACHE_VERSION) {
@ -15238,7 +15561,6 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char
auto access_hash = has_access_hash ? channel.access_hash_ : 0; auto access_hash = has_access_hash ? channel.access_hash_ : 0;
bool has_linked_channel = (channel.flags_ & CHANNEL_FLAG_HAS_LINKED_CHAT) != 0; bool has_linked_channel = (channel.flags_ & CHANNEL_FLAG_HAS_LINKED_CHAT) != 0;
bool has_location = (channel.flags_ & CHANNEL_FLAG_HAS_LOCATION) != 0;
bool sign_messages = (channel.flags_ & CHANNEL_FLAG_SIGN_MESSAGES) != 0; bool sign_messages = (channel.flags_ & CHANNEL_FLAG_SIGN_MESSAGES) != 0;
bool is_slow_mode_enabled = (channel.flags_ & CHANNEL_FLAG_IS_SLOW_MODE_ENABLED) != 0; bool is_slow_mode_enabled = (channel.flags_ & CHANNEL_FLAG_IS_SLOW_MODE_ENABLED) != 0;
bool is_megagroup = (channel.flags_ & CHANNEL_FLAG_IS_MEGAGROUP) != 0; bool is_megagroup = (channel.flags_ & CHANNEL_FLAG_IS_MEGAGROUP) != 0;
@ -15306,13 +15628,13 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char
on_update_channel_photo(c, channel_id, std::move(channel.photo_)); on_update_channel_photo(c, channel_id, std::move(channel.photo_));
on_update_channel_default_permissions(c, channel_id, on_update_channel_default_permissions(c, channel_id,
get_restricted_rights(std::move(channel.default_banned_rights_))); get_restricted_rights(std::move(channel.default_banned_rights_)));
on_update_channel_has_location(c, channel_id, channel.has_geo_);
on_update_channel_noforwards(c, channel_id, channel.noforwards_);
if (c->has_linked_channel != has_linked_channel || c->has_location != has_location || if (c->has_linked_channel != has_linked_channel || c->is_slow_mode_enabled != is_slow_mode_enabled ||
c->is_slow_mode_enabled != is_slow_mode_enabled || c->is_megagroup != is_megagroup || c->is_megagroup != is_megagroup || c->restriction_reasons != restriction_reasons || c->is_scam != is_scam ||
c->restriction_reasons != restriction_reasons || c->is_scam != is_scam || c->is_fake != is_fake || c->is_fake != is_fake || c->is_gigagroup != is_gigagroup) {
c->is_gigagroup != is_gigagroup) {
c->has_linked_channel = has_linked_channel; c->has_linked_channel = has_linked_channel;
c->has_location = has_location;
c->is_slow_mode_enabled = is_slow_mode_enabled; c->is_slow_mode_enabled = is_slow_mode_enabled;
c->is_megagroup = is_megagroup; c->is_megagroup = is_megagroup;
c->restriction_reasons = std::move(restriction_reasons); c->restriction_reasons = std::move(restriction_reasons);
@ -15364,6 +15686,8 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char
on_update_channel_username(c, channel_id, std::move(channel.username_)); // uses status, must be called after on_update_channel_username(c, channel_id, std::move(channel.username_)); // uses status, must be called after
on_update_channel_default_permissions(c, channel_id, on_update_channel_default_permissions(c, channel_id,
get_restricted_rights(std::move(channel.default_banned_rights_))); get_restricted_rights(std::move(channel.default_banned_rights_)));
on_update_channel_has_location(c, channel_id, channel.has_geo_);
on_update_channel_noforwards(c, channel_id, channel.noforwards_);
bool need_update_participant_count = have_participant_count && participant_count != c->participant_count; bool need_update_participant_count = have_participant_count && participant_count != c->participant_count;
if (need_update_participant_count) { if (need_update_participant_count) {
@ -15372,12 +15696,10 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char
} }
bool need_invalidate_channel_full = false; bool need_invalidate_channel_full = false;
if (c->has_linked_channel != has_linked_channel || c->has_location != has_location || if (c->has_linked_channel != has_linked_channel || c->is_slow_mode_enabled != is_slow_mode_enabled ||
c->is_slow_mode_enabled != is_slow_mode_enabled || c->is_megagroup != is_megagroup || c->is_megagroup != is_megagroup || c->restriction_reasons != restriction_reasons || c->is_scam != is_scam ||
c->restriction_reasons != restriction_reasons || c->is_scam != is_scam || c->is_fake != is_fake || c->is_fake != is_fake || c->is_gigagroup != is_gigagroup) {
c->is_gigagroup != is_gigagroup) {
c->has_linked_channel = has_linked_channel; c->has_linked_channel = has_linked_channel;
c->has_location = has_location;
c->is_slow_mode_enabled = is_slow_mode_enabled; c->is_slow_mode_enabled = is_slow_mode_enabled;
c->is_megagroup = is_megagroup; c->is_megagroup = is_megagroup;
c->restriction_reasons = std::move(restriction_reasons); c->restriction_reasons = std::move(restriction_reasons);
@ -15457,6 +15779,8 @@ void ContactsManager::on_chat_update(telegram_api::channelForbidden &channel, co
// on_update_channel_username(c, channel_id, ""); // don't know if channel username is empty, so don't update it // on_update_channel_username(c, channel_id, ""); // don't know if channel username is empty, so don't update it
tl_object_ptr<telegram_api::chatBannedRights> banned_rights; // == nullptr tl_object_ptr<telegram_api::chatBannedRights> banned_rights; // == nullptr
on_update_channel_default_permissions(c, channel_id, get_restricted_rights(std::move(banned_rights))); on_update_channel_default_permissions(c, channel_id, get_restricted_rights(std::move(banned_rights)));
// on_update_channel_has_location(c, channel_id, false);
on_update_channel_noforwards(c, channel_id, false);
td_->messages_manager_->on_update_dialog_group_call(DialogId(channel_id), false, false, "receive channelForbidden"); td_->messages_manager_->on_update_dialog_group_call(DialogId(channel_id), false, false, "receive channelForbidden");
bool sign_messages = false; bool sign_messages = false;
@ -15481,7 +15805,6 @@ void ContactsManager::on_chat_update(telegram_api::channelForbidden &channel, co
if (c->is_slow_mode_enabled != is_slow_mode_enabled || c->is_megagroup != is_megagroup || if (c->is_slow_mode_enabled != is_slow_mode_enabled || c->is_megagroup != is_megagroup ||
!c->restriction_reasons.empty() || c->is_scam != is_scam || c->is_fake != is_fake) { !c->restriction_reasons.empty() || c->is_scam != is_scam || c->is_fake != is_fake) {
// c->has_linked_channel = has_linked_channel; // c->has_linked_channel = has_linked_channel;
// c->has_location = has_location;
c->is_slow_mode_enabled = is_slow_mode_enabled; c->is_slow_mode_enabled = is_slow_mode_enabled;
c->is_megagroup = is_megagroup; c->is_megagroup = is_megagroup;
c->restriction_reasons.clear(); c->restriction_reasons.clear();
@ -15698,9 +16021,9 @@ tl_object_ptr<td_api::userFullInfo> ContactsManager::get_user_full_info_object(U
return make_tl_object<td_api::userFullInfo>( return make_tl_object<td_api::userFullInfo>(
get_chat_photo_object(td_->file_manager_.get(), user_full->photo), user_full->is_blocked, get_chat_photo_object(td_->file_manager_.get(), user_full->photo), user_full->is_blocked,
user_full->can_be_called, user_full->supports_video_calls, user_full->has_private_calls, user_full->can_be_called, user_full->supports_video_calls, user_full->has_private_calls,
user_full->need_phone_number_privacy_exception, is_bot ? string() : user_full->about, !user_full->private_forward_name.empty(), user_full->need_phone_number_privacy_exception,
is_bot ? user_full->about : string(), is_bot ? user_full->description : string(), user_full->common_chat_count, is_bot ? string() : user_full->about, is_bot ? user_full->about : string(),
std::move(commands)); is_bot ? user_full->description : string(), user_full->common_chat_count, std::move(commands));
} }
td_api::object_ptr<td_api::updateBasicGroup> ContactsManager::get_update_unknown_basic_group_object(ChatId chat_id) { td_api::object_ptr<td_api::updateBasicGroup> ContactsManager::get_update_unknown_basic_group_object(ChatId chat_id) {
@ -15976,6 +16299,11 @@ void ContactsManager::after_get_difference() {
return; return;
} }
get_user(get_my_id(), 3, Promise<Unit>()); get_user(get_my_id(), 3, Promise<Unit>());
if (td_->is_online()) {
reload_created_public_dialogs(PublicDialogType::HasUsername, Promise<td_api::object_ptr<td_api::chats>>());
reload_created_public_dialogs(PublicDialogType::IsLocationBased, Promise<td_api::object_ptr<td_api::chats>>());
}
} }
void ContactsManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const { void ContactsManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const {

View File

@ -109,6 +109,11 @@ class ContactsManager final : public Actor {
RestrictedRights get_channel_default_permissions(ChannelId channel_id) const; RestrictedRights get_channel_default_permissions(ChannelId channel_id) const;
RestrictedRights get_secret_chat_default_permissions(SecretChatId secret_chat_id) const; RestrictedRights get_secret_chat_default_permissions(SecretChatId secret_chat_id) const;
bool get_chat_has_protected_content(ChatId chat_id) const;
bool get_channel_has_protected_content(ChannelId channel_id) const;
string get_user_private_forward_name(UserId user_id);
string get_dialog_about(DialogId dialog_id); string get_dialog_about(DialogId dialog_id);
bool is_update_about_username_change_received(UserId user_id) const; bool is_update_about_username_change_received(UserId user_id) const;
@ -341,8 +346,7 @@ class ContactsManager final : public Actor {
void set_channel_slow_mode_delay(DialogId dialog_id, int32 slow_mode_delay, Promise<Unit> &&promise); void set_channel_slow_mode_delay(DialogId dialog_id, int32 slow_mode_delay, Promise<Unit> &&promise);
void report_channel_spam(ChannelId channel_id, UserId user_id, const vector<MessageId> &message_ids, void report_channel_spam(ChannelId channel_id, const vector<MessageId> &message_ids, Promise<Unit> &&promise);
Promise<Unit> &&promise);
void delete_dialog(DialogId dialog_id, Promise<Unit> &&promise); void delete_dialog(DialogId dialog_id, Promise<Unit> &&promise);
@ -397,7 +401,10 @@ class ContactsManager final : public Actor {
td_api::object_ptr<td_api::chatJoinRequest> offset_request, int32 limit, td_api::object_ptr<td_api::chatJoinRequest> offset_request, int32 limit,
Promise<td_api::object_ptr<td_api::chatJoinRequests>> &&promise); Promise<td_api::object_ptr<td_api::chatJoinRequests>> &&promise);
void process_dialog_join_requests(DialogId dialog_id, UserId user_id, bool is_approved, Promise<Unit> &&promise); void process_dialog_join_request(DialogId dialog_id, UserId user_id, bool approve, Promise<Unit> &&promise);
void process_dialog_join_requests(DialogId dialog_id, const string &invite_link, bool approve,
Promise<Unit> &&promise);
void revoke_dialog_invite_link(DialogId dialog_id, const string &link, void revoke_dialog_invite_link(DialogId dialog_id, const string &link,
Promise<td_api::object_ptr<td_api::chatInviteLinks>> &&promise); Promise<td_api::object_ptr<td_api::chatInviteLinks>> &&promise);
@ -412,7 +419,8 @@ class ContactsManager final : public Actor {
ChannelId migrate_chat_to_megagroup(ChatId chat_id, Promise<Unit> &promise); ChannelId migrate_chat_to_megagroup(ChatId chat_id, Promise<Unit> &promise);
vector<DialogId> get_created_public_dialogs(PublicDialogType type, Promise<Unit> &&promise); void get_created_public_dialogs(PublicDialogType type, Promise<td_api::object_ptr<td_api::chats>> &&promise,
bool from_binlog);
void check_created_public_dialogs_limit(PublicDialogType type, Promise<Unit> &&promise); void check_created_public_dialogs_limit(PublicDialogType type, Promise<Unit> &&promise);
@ -669,6 +677,7 @@ class ContactsManager final : public Actor {
string about; string about;
string description; string description;
string private_forward_name;
vector<BotCommand> commands; vector<BotCommand> commands;
@ -713,16 +722,18 @@ class ContactsManager final : public Actor {
DialogParticipantStatus status = DialogParticipantStatus::Banned(0); DialogParticipantStatus status = DialogParticipantStatus::Banned(0);
RestrictedRights default_permissions{false, false, false, false, false, false, false, false, false, false, false}; RestrictedRights default_permissions{false, false, false, false, false, false, false, false, false, false, false};
static constexpr uint32 CACHE_VERSION = 3; static constexpr uint32 CACHE_VERSION = 4;
uint32 cache_version = 0; uint32 cache_version = 0;
bool is_active = false; bool is_active = false;
bool noforwards = false;
bool is_title_changed = true; bool is_title_changed = true;
bool is_photo_changed = true; bool is_photo_changed = true;
bool is_default_permissions_changed = true; bool is_default_permissions_changed = true;
bool is_status_changed = true; bool is_status_changed = true;
bool is_is_active_changed = true; bool is_is_active_changed = true;
bool is_noforwards_changed = true;
bool is_changed = true; // have new changes that need to be sent to the client and database bool is_changed = true; // have new changes that need to be sent to the client and database
bool need_save_to_database = true; // have new changes that need only to be saved to the database bool need_save_to_database = true; // have new changes that need only to be saved to the database
bool is_update_basic_group_sent = false; bool is_update_basic_group_sent = false;
@ -784,13 +795,14 @@ class ContactsManager final : public Actor {
int32 date = 0; int32 date = 0;
int32 participant_count = 0; int32 participant_count = 0;
static constexpr uint32 CACHE_VERSION = 7; static constexpr uint32 CACHE_VERSION = 8;
uint32 cache_version = 0; uint32 cache_version = 0;
bool has_linked_channel = false; bool has_linked_channel = false;
bool has_location = false; bool has_location = false;
bool sign_messages = false; bool sign_messages = false;
bool is_slow_mode_enabled = false; bool is_slow_mode_enabled = false;
bool noforwards = false;
bool is_megagroup = false; bool is_megagroup = false;
bool is_gigagroup = false; bool is_gigagroup = false;
@ -803,6 +815,9 @@ class ContactsManager final : public Actor {
bool is_photo_changed = true; bool is_photo_changed = true;
bool is_default_permissions_changed = true; bool is_default_permissions_changed = true;
bool is_status_changed = true; bool is_status_changed = true;
bool is_has_location_changed = true;
bool is_noforwards_changed = true;
bool is_creator_changed = true;
bool had_read_access = true; bool had_read_access = true;
bool was_member = false; bool was_member = false;
bool is_changed = true; // have new changes that need to be sent to the client and database bool is_changed = true; // have new changes that need to be sent to the client and database
@ -1009,6 +1024,7 @@ class ContactsManager final : public Actor {
static constexpr int32 USER_FULL_FLAG_HAS_FOLDER_ID = 1 << 11; static constexpr int32 USER_FULL_FLAG_HAS_FOLDER_ID = 1 << 11;
static constexpr int32 USER_FULL_FLAG_HAS_SCHEDULED_MESSAGES = 1 << 12; static constexpr int32 USER_FULL_FLAG_HAS_SCHEDULED_MESSAGES = 1 << 12;
static constexpr int32 USER_FULL_FLAG_HAS_MESSAGE_TTL = 1 << 14; static constexpr int32 USER_FULL_FLAG_HAS_MESSAGE_TTL = 1 << 14;
static constexpr int32 USER_FULL_FLAG_HAS_PRIVATE_FORWARD_NAME = 1 << 16;
static constexpr int32 CHAT_FLAG_USER_IS_CREATOR = 1 << 0; static constexpr int32 CHAT_FLAG_USER_IS_CREATOR = 1 << 0;
static constexpr int32 CHAT_FLAG_USER_WAS_KICKED = 1 << 1; static constexpr int32 CHAT_FLAG_USER_WAS_KICKED = 1 << 1;
@ -1077,6 +1093,7 @@ class ContactsManager final : public Actor {
static constexpr int32 CHANNEL_FULL_FLAG_HAS_EXPORTED_INVITE = 1 << 23; static constexpr int32 CHANNEL_FULL_FLAG_HAS_EXPORTED_INVITE = 1 << 23;
static constexpr int32 CHANNEL_FULL_FLAG_HAS_MESSAGE_TTL = 1 << 24; static constexpr int32 CHANNEL_FULL_FLAG_HAS_MESSAGE_TTL = 1 << 24;
static constexpr int32 CHANNEL_FULL_FLAG_HAS_PENDING_REQUEST_COUNT = 1 << 28; 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 CHAT_INVITE_FLAG_IS_CHANNEL = 1 << 0; static constexpr int32 CHAT_INVITE_FLAG_IS_CHANNEL = 1 << 0;
static constexpr int32 CHAT_INVITE_FLAG_IS_BROADCAST = 1 << 1; static constexpr int32 CHAT_INVITE_FLAG_IS_BROADCAST = 1 << 1;
@ -1204,6 +1221,7 @@ class ContactsManager final : public Actor {
static void on_update_chat_title(Chat *c, ChatId chat_id, string &&title); static void on_update_chat_title(Chat *c, ChatId chat_id, string &&title);
static void on_update_chat_active(Chat *c, ChatId chat_id, bool is_active); static void on_update_chat_active(Chat *c, ChatId chat_id, bool is_active);
static void on_update_chat_migrated_to_channel_id(Chat *c, ChatId chat_id, ChannelId migrated_to_channel_id); static void on_update_chat_migrated_to_channel_id(Chat *c, ChatId chat_id, ChannelId migrated_to_channel_id);
static void on_update_chat_noforwards(Chat *c, ChatId chat_id, bool noforwards);
void on_update_chat_full_photo(ChatFull *chat_full, ChatId chat_id, Photo photo); void on_update_chat_full_photo(ChatFull *chat_full, ChatId chat_id, Photo photo);
bool on_update_chat_full_participants_short(ChatFull *chat_full, ChatId chat_id, int32 version); bool on_update_chat_full_participants_short(ChatFull *chat_full, ChatId chat_id, int32 version);
@ -1219,6 +1237,8 @@ class ContactsManager final : public Actor {
void on_update_channel_status(Channel *c, ChannelId channel_id, DialogParticipantStatus &&status); void on_update_channel_status(Channel *c, ChannelId channel_id, DialogParticipantStatus &&status);
static void on_update_channel_default_permissions(Channel *c, ChannelId channel_id, static void on_update_channel_default_permissions(Channel *c, ChannelId channel_id,
RestrictedRights default_permissions); RestrictedRights default_permissions);
static void on_update_channel_has_location(Channel *c, ChannelId channel_id, bool has_location);
static void on_update_channel_noforwards(Channel *c, ChannelId channel_id, bool noforwards);
void on_update_channel_bot_user_ids(ChannelId channel_id, vector<UserId> &&bot_user_ids); void on_update_channel_bot_user_ids(ChannelId channel_id, vector<UserId> &&bot_user_ids);
@ -1235,7 +1255,7 @@ class ContactsManager final : public Actor {
static void on_update_channel_full_bot_user_ids(ChannelFull *channel_full, ChannelId channel_id, static void on_update_channel_full_bot_user_ids(ChannelFull *channel_full, ChannelId channel_id,
vector<UserId> &&bot_user_ids); vector<UserId> &&bot_user_ids);
void on_channel_status_changed(const Channel *c, ChannelId channel_id, const DialogParticipantStatus &old_status, void on_channel_status_changed(Channel *c, ChannelId channel_id, const DialogParticipantStatus &old_status,
const DialogParticipantStatus &new_status); const DialogParticipantStatus &new_status);
void on_channel_username_changed(const Channel *c, ChannelId channel_id, const string &old_username, void on_channel_username_changed(const Channel *c, ChannelId channel_id, const string &old_username,
const string &new_username); const string &new_username);
@ -1255,7 +1275,7 @@ class ContactsManager final : public Actor {
void drop_channel_photos(ChannelId channel_id, bool is_empty, bool drop_channel_full_photo, const char *source); void drop_channel_photos(ChannelId channel_id, bool is_empty, bool drop_channel_full_photo, const char *source);
static void do_invalidate_channel_full(ChannelFull *channel_full, bool need_drop_slow_mode_delay); void do_invalidate_channel_full(ChannelFull *channel_full, ChannelId channel_id, bool need_drop_slow_mode_delay);
void update_user_online_member_count(User *u); void update_user_online_member_count(User *u);
void update_chat_online_member_count(const ChatFull *chat_full, ChatId chat_id, bool is_from_server); void update_chat_online_member_count(const ChatFull *chat_full, ChatId chat_id, bool is_from_server);
@ -1393,6 +1413,19 @@ class ContactsManager final : public Actor {
static bool is_channel_public(const Channel *c); static bool is_channel_public(const Channel *c);
static void return_created_public_dialogs(Promise<td_api::object_ptr<td_api::chats>> &&promise,
const vector<ChannelId> &channel_ids);
void reload_created_public_dialogs(PublicDialogType type, Promise<td_api::object_ptr<td_api::chats>> &&promise);
void finish_get_created_public_dialogs(PublicDialogType type, Result<Unit> &&result);
void update_created_public_channels(Channel *c, ChannelId channel_id);
void save_created_public_channels(PublicDialogType type);
void update_created_public_broadcasts();
void export_dialog_invite_link_impl(DialogId dialog_id, string title, int32 expire_date, int32 usage_limit, void export_dialog_invite_link_impl(DialogId dialog_id, string title, int32 expire_date, int32 usage_limit,
bool creates_join_request, bool is_permanent, bool creates_join_request, bool is_permanent,
Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise); Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise);
@ -1626,6 +1659,7 @@ class ContactsManager final : public Actor {
bool created_public_channels_inited_[2] = {false, false}; bool created_public_channels_inited_[2] = {false, false};
vector<ChannelId> created_public_channels_[2]; vector<ChannelId> created_public_channels_[2];
vector<Promise<td_api::object_ptr<td_api::chats>>> get_created_public_channels_queries_[2];
bool dialogs_for_discussion_inited_ = false; bool dialogs_for_discussion_inited_ = false;
vector<DialogId> dialogs_for_discussion_; vector<DialogId> dialogs_for_discussion_;
@ -1650,7 +1684,6 @@ class ContactsManager final : public Actor {
QueryCombiner get_user_full_queries_{"GetUserFullCombiner", 2.0}; QueryCombiner get_user_full_queries_{"GetUserFullCombiner", 2.0};
QueryCombiner get_chat_full_queries_{"GetChatFullCombiner", 2.0}; QueryCombiner get_chat_full_queries_{"GetChatFullCombiner", 2.0};
QueryCombiner get_channel_full_queries_{"GetChannelFullCombiner", 2.0};
std::unordered_map<DialogId, vector<DialogAdministrator>, DialogIdHash> dialog_administrators_; std::unordered_map<DialogId, vector<DialogAdministrator>, DialogIdHash> dialog_administrators_;

View File

@ -13,9 +13,11 @@ namespace td {
unique_ptr<DialogActionBar> DialogActionBar::create(bool can_report_spam, bool can_add_contact, bool can_block_user, unique_ptr<DialogActionBar> DialogActionBar::create(bool can_report_spam, bool can_add_contact, bool can_block_user,
bool can_share_phone_number, bool can_report_location, bool can_share_phone_number, bool can_report_location,
bool can_unarchive, int32 distance, bool can_invite_members) { bool can_unarchive, int32 distance, bool can_invite_members,
string join_request_dialog_title, bool is_join_request_broadcast,
int32 join_request_date) {
if (!can_report_spam && !can_add_contact && !can_block_user && !can_share_phone_number && !can_report_location && if (!can_report_spam && !can_add_contact && !can_block_user && !can_share_phone_number && !can_report_location &&
!can_invite_members) { !can_invite_members && join_request_dialog_title.empty()) {
return nullptr; return nullptr;
} }
@ -28,29 +30,59 @@ unique_ptr<DialogActionBar> DialogActionBar::create(bool can_report_spam, bool c
action_bar->can_unarchive_ = can_unarchive; action_bar->can_unarchive_ = can_unarchive;
action_bar->distance_ = distance >= 0 ? distance : -1; action_bar->distance_ = distance >= 0 ? distance : -1;
action_bar->can_invite_members_ = can_invite_members; action_bar->can_invite_members_ = can_invite_members;
action_bar->join_request_dialog_title_ = std::move(join_request_dialog_title);
action_bar->is_join_request_broadcast_ = is_join_request_broadcast;
action_bar->join_request_date_ = join_request_date;
return action_bar; return action_bar;
} }
bool DialogActionBar::is_empty() const { bool DialogActionBar::is_empty() const {
return !can_report_spam_ && !can_add_contact_ && !can_block_user_ && !can_share_phone_number_ && return !can_report_spam_ && !can_add_contact_ && !can_block_user_ && !can_share_phone_number_ &&
!can_report_location_ && !can_invite_members_; !can_report_location_ && !can_invite_members_ && join_request_dialog_title_.empty();
} }
void DialogActionBar::fix(Td *td, DialogId dialog_id, bool is_dialog_blocked, FolderId folder_id) { void DialogActionBar::fix(Td *td, DialogId dialog_id, bool is_dialog_blocked, FolderId folder_id) {
auto dialog_type = dialog_id.get_type(); auto dialog_type = dialog_id.get_type();
if (distance_ >= 0 && dialog_type != DialogType::User) { if (distance_ >= 0 && dialog_type != DialogType::User) {
LOG(ERROR) << "Receive distance_ " << distance_ << " to " << dialog_id; LOG(ERROR) << "Receive distance " << distance_ << " to " << dialog_id;
distance_ = -1; distance_ = -1;
} }
if (!join_request_dialog_title_.empty()) {
if (dialog_type != DialogType::User || join_request_date_ <= 0) {
LOG(ERROR) << "Receive join_request_date = " << join_request_date_ << " in " << dialog_id;
join_request_dialog_title_.clear();
is_join_request_broadcast_ = false;
join_request_date_ = 0;
} else if (can_report_location_ || can_report_spam_ || can_add_contact_ || can_block_user_ ||
can_share_phone_number_ || can_unarchive_ || can_invite_members_) {
LOG(ERROR) << "Receive action bar " << can_report_location_ << '/' << can_report_spam_ << '/' << can_add_contact_
<< '/' << can_block_user_ << '/' << can_share_phone_number_ << '/' << can_report_location_ << '/'
<< can_unarchive_ << '/' << can_invite_members_;
can_report_location_ = false;
can_report_spam_ = false;
can_add_contact_ = false;
can_block_user_ = false;
can_share_phone_number_ = false;
can_unarchive_ = false;
can_invite_members_ = false;
distance_ = -1;
}
}
if (join_request_dialog_title_.empty() && (is_join_request_broadcast_ || join_request_date_ != 0)) {
LOG(ERROR) << "Receive join request date = " << join_request_date_ << " and " << is_join_request_broadcast_
<< " in " << dialog_id;
is_join_request_broadcast_ = false;
join_request_date_ = 0;
}
if (can_report_location_) { if (can_report_location_) {
if (dialog_type != DialogType::Channel) { if (dialog_type != DialogType::Channel) {
LOG(ERROR) << "Receive can_report_location_ in " << dialog_id; LOG(ERROR) << "Receive can_report_location in " << dialog_id;
can_report_location_ = false; can_report_location_ = false;
} else if (can_report_spam_ || can_add_contact_ || can_block_user_ || can_share_phone_number_ || can_unarchive_ || } else if (can_report_spam_ || can_add_contact_ || can_block_user_ || can_share_phone_number_ || can_unarchive_ ||
can_invite_members_) { can_invite_members_) {
LOG(ERROR) << "Receive action bar " << can_report_spam_ << "/" << can_add_contact_ << "/" << can_block_user_ LOG(ERROR) << "Receive action bar " << can_report_spam_ << '/' << can_add_contact_ << '/' << can_block_user_
<< "/" << can_share_phone_number_ << "/" << can_report_location_ << "/" << can_unarchive_ << "/" << '/' << can_share_phone_number_ << '/' << can_report_location_ << '/' << can_unarchive_ << '/'
<< can_invite_members_; << can_invite_members_;
can_report_spam_ = false; can_report_spam_ = false;
can_add_contact_ = false; can_add_contact_ = false;
@ -65,11 +97,11 @@ void DialogActionBar::fix(Td *td, DialogId dialog_id, bool is_dialog_blocked, Fo
if (dialog_type != DialogType::Chat && if (dialog_type != DialogType::Chat &&
(dialog_type != DialogType::Channel || td->contacts_manager_->get_channel_type(dialog_id.get_channel_id()) == (dialog_type != DialogType::Channel || td->contacts_manager_->get_channel_type(dialog_id.get_channel_id()) ==
ContactsManager::ChannelType::Broadcast)) { ContactsManager::ChannelType::Broadcast)) {
LOG(ERROR) << "Receive can_invite_members_ in " << dialog_id; LOG(ERROR) << "Receive can_invite_members in " << dialog_id;
can_invite_members_ = false; can_invite_members_ = false;
} else if (can_report_spam_ || can_add_contact_ || can_block_user_ || can_share_phone_number_ || can_unarchive_) { } else if (can_report_spam_ || can_add_contact_ || can_block_user_ || can_share_phone_number_ || can_unarchive_) {
LOG(ERROR) << "Receive action bar " << can_report_spam_ << "/" << can_add_contact_ << "/" << can_block_user_ LOG(ERROR) << "Receive action bar " << can_report_spam_ << '/' << can_add_contact_ << '/' << can_block_user_
<< "/" << can_share_phone_number_ << "/" << can_unarchive_ << "/" << can_invite_members_; << '/' << can_share_phone_number_ << '/' << can_unarchive_ << '/' << can_invite_members_;
can_report_spam_ = false; can_report_spam_ = false;
can_add_contact_ = false; can_add_contact_ = false;
can_block_user_ = false; can_block_user_ = false;
@ -102,11 +134,11 @@ void DialogActionBar::fix(Td *td, DialogId dialog_id, bool is_dialog_blocked, Fo
CHECK(!can_report_location_); CHECK(!can_report_location_);
CHECK(!can_invite_members_); CHECK(!can_invite_members_);
if (dialog_type != DialogType::User) { if (dialog_type != DialogType::User) {
LOG(ERROR) << "Receive can_share_phone_number_ in " << dialog_id; LOG(ERROR) << "Receive can_share_phone_number in " << dialog_id;
can_share_phone_number_ = false; can_share_phone_number_ = false;
} else if (can_report_spam_ || can_add_contact_ || can_block_user_ || can_unarchive_ || distance_ >= 0) { } else if (can_report_spam_ || can_add_contact_ || can_block_user_ || can_unarchive_ || distance_ >= 0) {
LOG(ERROR) << "Receive action bar " << can_report_spam_ << "/" << can_add_contact_ << "/" << can_block_user_ LOG(ERROR) << "Receive action bar " << can_report_spam_ << '/' << can_add_contact_ << '/' << can_block_user_
<< "/" << can_share_phone_number_ << "/" << can_unarchive_ << "/" << distance_; << '/' << can_share_phone_number_ << '/' << can_unarchive_ << '/' << distance_;
can_report_spam_ = false; can_report_spam_ = false;
can_add_contact_ = false; can_add_contact_ = false;
can_block_user_ = false; can_block_user_ = false;
@ -118,10 +150,10 @@ void DialogActionBar::fix(Td *td, DialogId dialog_id, bool is_dialog_blocked, Fo
CHECK(!can_invite_members_); CHECK(!can_invite_members_);
CHECK(!can_share_phone_number_); CHECK(!can_share_phone_number_);
if (dialog_type != DialogType::User) { if (dialog_type != DialogType::User) {
LOG(ERROR) << "Receive can_block_user_ in " << dialog_id; LOG(ERROR) << "Receive can_block_user in " << dialog_id;
can_block_user_ = false; can_block_user_ = false;
} else if (!can_report_spam_ || !can_add_contact_) { } else if (!can_report_spam_ || !can_add_contact_) {
LOG(ERROR) << "Receive action bar " << can_report_spam_ << "/" << can_add_contact_ << "/" << can_block_user_; LOG(ERROR) << "Receive action bar " << can_report_spam_ << '/' << can_add_contact_ << '/' << can_block_user_;
can_report_spam_ = true; can_report_spam_ = true;
can_add_contact_ = true; can_add_contact_ = true;
} }
@ -131,10 +163,10 @@ void DialogActionBar::fix(Td *td, DialogId dialog_id, bool is_dialog_blocked, Fo
CHECK(!can_invite_members_); CHECK(!can_invite_members_);
CHECK(!can_share_phone_number_); CHECK(!can_share_phone_number_);
if (dialog_type != DialogType::User) { if (dialog_type != DialogType::User) {
LOG(ERROR) << "Receive can_add_contact_ in " << dialog_id; LOG(ERROR) << "Receive can_add_contact in " << dialog_id;
can_add_contact_ = false; can_add_contact_ = false;
} else if (can_report_spam_ != can_block_user_) { } else if (can_report_spam_ != can_block_user_) {
LOG(ERROR) << "Receive action bar " << can_report_spam_ << "/" << can_add_contact_ << "/" << can_block_user_; LOG(ERROR) << "Receive action bar " << can_report_spam_ << '/' << can_add_contact_ << '/' << can_block_user_;
can_report_spam_ = false; can_report_spam_ = false;
can_block_user_ = false; can_block_user_ = false;
can_unarchive_ = false; can_unarchive_ = false;
@ -150,6 +182,13 @@ void DialogActionBar::fix(Td *td, DialogId dialog_id, bool is_dialog_blocked, Fo
td_api::object_ptr<td_api::ChatActionBar> DialogActionBar::get_chat_action_bar_object(DialogType dialog_type, td_api::object_ptr<td_api::ChatActionBar> DialogActionBar::get_chat_action_bar_object(DialogType dialog_type,
bool hide_unarchive) const { bool hide_unarchive) const {
if (!join_request_dialog_title_.empty()) {
CHECK(dialog_type == DialogType::User);
CHECK(!can_report_location_ && !can_share_phone_number_ && !can_block_user_ && !can_add_contact_ &&
!can_report_spam_ && !can_invite_members_);
return td_api::make_object<td_api::chatActionBarJoinRequest>(join_request_dialog_title_, is_join_request_broadcast_,
join_request_date_);
}
if (can_report_location_) { if (can_report_location_) {
CHECK(dialog_type == DialogType::Channel); CHECK(dialog_type == DialogType::Channel);
CHECK(!can_share_phone_number_ && !can_block_user_ && !can_add_contact_ && !can_report_spam_ && CHECK(!can_share_phone_number_ && !can_block_user_ && !can_add_contact_ && !can_report_spam_ &&
@ -213,10 +252,14 @@ bool DialogActionBar::on_user_contact_added() {
} }
bool DialogActionBar::on_user_deleted() { bool DialogActionBar::on_user_deleted() {
if (!can_share_phone_number_ && !can_block_user_ && !can_add_contact_ && distance_ < 0) { if (join_request_dialog_title_.empty() && !can_share_phone_number_ && !can_block_user_ && !can_add_contact_ &&
distance_ < 0) {
return false; return false;
} }
join_request_dialog_title_.clear();
is_join_request_broadcast_ = false;
join_request_date_ = 0;
can_share_phone_number_ = false; can_share_phone_number_ = false;
can_block_user_ = false; can_block_user_ = false;
can_add_contact_ = false; can_add_contact_ = false;
@ -243,7 +286,11 @@ bool operator==(const unique_ptr<DialogActionBar> &lhs, const unique_ptr<DialogA
return lhs->can_report_spam_ == rhs->can_report_spam_ && lhs->can_add_contact_ == rhs->can_add_contact_ && return lhs->can_report_spam_ == rhs->can_report_spam_ && lhs->can_add_contact_ == rhs->can_add_contact_ &&
lhs->can_block_user_ == rhs->can_block_user_ && lhs->can_share_phone_number_ == rhs->can_share_phone_number_ && lhs->can_block_user_ == rhs->can_block_user_ && lhs->can_share_phone_number_ == rhs->can_share_phone_number_ &&
lhs->can_report_location_ == rhs->can_report_location_ && lhs->can_unarchive_ == rhs->can_unarchive_ && lhs->can_report_location_ == rhs->can_report_location_ && lhs->can_unarchive_ == rhs->can_unarchive_ &&
lhs->distance_ == rhs->distance_ && lhs->can_invite_members_ == rhs->can_invite_members_; lhs->distance_ == rhs->distance_ && lhs->can_invite_members_ == rhs->can_invite_members_ &&
lhs->join_request_dialog_title_ == rhs->join_request_dialog_title_ &&
lhs->is_join_request_broadcast_ == lhs->is_join_request_broadcast_ &&
lhs->join_request_date_ == rhs->join_request_date_;
;
} }
} // namespace td } // namespace td

View File

@ -19,6 +19,8 @@ class Td;
class DialogActionBar { class DialogActionBar {
int32 distance_ = -1; // distance to the peer int32 distance_ = -1; // distance to the peer
int32 join_request_date_ = 0;
string join_request_dialog_title_;
bool can_report_spam_ = false; bool can_report_spam_ = false;
bool can_add_contact_ = false; bool can_add_contact_ = false;
@ -27,13 +29,15 @@ class DialogActionBar {
bool can_report_location_ = false; bool can_report_location_ = false;
bool can_unarchive_ = false; bool can_unarchive_ = false;
bool can_invite_members_ = false; bool can_invite_members_ = false;
bool is_join_request_broadcast_ = false;
friend bool operator==(const unique_ptr<DialogActionBar> &lhs, const unique_ptr<DialogActionBar> &rhs); friend bool operator==(const unique_ptr<DialogActionBar> &lhs, const unique_ptr<DialogActionBar> &rhs);
public: public:
static unique_ptr<DialogActionBar> create(bool can_report_spam, bool can_add_contact, bool can_block_user, static unique_ptr<DialogActionBar> create(bool can_report_spam, bool can_add_contact, bool can_block_user,
bool can_share_phone_number, bool can_report_location, bool can_unarchive, bool can_share_phone_number, bool can_report_location, bool can_unarchive,
int32 distance, bool can_invite_members); int32 distance, bool can_invite_members, string join_request_dialog_title,
bool is_join_request_broadcast, int32 join_request_date);
bool is_empty() const; bool is_empty() const;
@ -61,6 +65,7 @@ class DialogActionBar {
template <class StorerT> template <class StorerT>
void store(StorerT &storer) const { void store(StorerT &storer) const {
bool has_distance = distance_ >= 0; bool has_distance = distance_ >= 0;
bool has_join_request = !join_request_dialog_title_.empty();
BEGIN_STORE_FLAGS(); BEGIN_STORE_FLAGS();
STORE_FLAG(can_report_spam_); STORE_FLAG(can_report_spam_);
STORE_FLAG(can_add_contact_); STORE_FLAG(can_add_contact_);
@ -70,15 +75,22 @@ class DialogActionBar {
STORE_FLAG(can_unarchive_); STORE_FLAG(can_unarchive_);
STORE_FLAG(can_invite_members_); STORE_FLAG(can_invite_members_);
STORE_FLAG(has_distance); STORE_FLAG(has_distance);
STORE_FLAG(is_join_request_broadcast_);
STORE_FLAG(has_join_request);
END_STORE_FLAGS(); END_STORE_FLAGS();
if (has_distance) { if (has_distance) {
td::store(distance_, storer); td::store(distance_, storer);
} }
if (has_join_request) {
td::store(join_request_dialog_title_, storer);
td::store(join_request_date_, storer);
}
} }
template <class ParserT> template <class ParserT>
void parse(ParserT &parser) { void parse(ParserT &parser) {
bool has_distance; bool has_distance;
bool has_join_request;
BEGIN_PARSE_FLAGS(); BEGIN_PARSE_FLAGS();
PARSE_FLAG(can_report_spam_); PARSE_FLAG(can_report_spam_);
PARSE_FLAG(can_add_contact_); PARSE_FLAG(can_add_contact_);
@ -88,10 +100,16 @@ class DialogActionBar {
PARSE_FLAG(can_unarchive_); PARSE_FLAG(can_unarchive_);
PARSE_FLAG(can_invite_members_); PARSE_FLAG(can_invite_members_);
PARSE_FLAG(has_distance); PARSE_FLAG(has_distance);
PARSE_FLAG(is_join_request_broadcast_);
PARSE_FLAG(has_join_request);
END_PARSE_FLAGS(); END_PARSE_FLAGS();
if (has_distance) { if (has_distance) {
td::parse(distance_, parser); td::parse(distance_, parser);
} }
if (has_join_request) {
td::parse(join_request_dialog_title_, parser);
td::parse(join_request_date_, parser);
}
} }
}; };

View File

@ -161,6 +161,9 @@ static td_api::object_ptr<td_api::ChatEventAction> get_chat_event_action_object(
return td_api::make_object<td_api::chatEventMessageUnpinned>(std::move(message)); return td_api::make_object<td_api::chatEventMessageUnpinned>(std::move(message));
} }
} }
case telegram_api::channelAdminLogEventActionSendMessage::ID: {
return nullptr;
}
case telegram_api::channelAdminLogEventActionEditMessage::ID: { case telegram_api::channelAdminLogEventActionEditMessage::ID: {
auto action = move_tl_object_as<telegram_api::channelAdminLogEventActionEditMessage>(action_ptr); auto action = move_tl_object_as<telegram_api::channelAdminLogEventActionEditMessage>(action_ptr);
auto old_message = td->messages_manager_->get_dialog_event_log_message_object(DialogId(channel_id), auto old_message = td->messages_manager_->get_dialog_event_log_message_object(DialogId(channel_id),
@ -326,6 +329,10 @@ static td_api::object_ptr<td_api::ChatEventAction> get_chat_event_action_object(
return td_api::make_object<td_api::chatEventMessageTtlSettingChanged>(old_value.get_message_ttl_setting_object(), return td_api::make_object<td_api::chatEventMessageTtlSettingChanged>(old_value.get_message_ttl_setting_object(),
new_value.get_message_ttl_setting_object()); new_value.get_message_ttl_setting_object());
} }
case telegram_api::channelAdminLogEventActionToggleNoForwards::ID: {
auto action = move_tl_object_as<telegram_api::channelAdminLogEventActionToggleNoForwards>(action_ptr);
return td_api::make_object<td_api::chatEventHasProtectedContentToggled>(action->new_value_);
}
default: default:
UNREACHABLE(); UNREACHABLE();
return nullptr; return nullptr;
@ -456,7 +463,7 @@ static telegram_api::object_ptr<telegram_api::channelAdminLogEventsFilter> get_i
return telegram_api::make_object<telegram_api::channelAdminLogEventsFilter>( return telegram_api::make_object<telegram_api::channelAdminLogEventsFilter>(
flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/); false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/);
} }
void get_dialog_event_log(Td *td, DialogId dialog_id, const string &query, int64 from_event_id, int32 limit, void get_dialog_event_log(Td *td, DialogId dialog_id, const string &query, int64 from_event_id, int32 limit,

View File

@ -191,7 +191,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
db_.get_statement("DELETE FROM messages WHERE dialog_id = ?1 AND message_id = ?2")); db_.get_statement("DELETE FROM messages WHERE dialog_id = ?1 AND message_id = ?2"));
TRY_RESULT_ASSIGN(delete_all_dialog_messages_stmt_, TRY_RESULT_ASSIGN(delete_all_dialog_messages_stmt_,
db_.get_statement("DELETE FROM messages WHERE dialog_id = ?1 AND message_id <= ?2")); db_.get_statement("DELETE FROM messages WHERE dialog_id = ?1 AND message_id <= ?2"));
TRY_RESULT_ASSIGN(delete_dialog_messages_from_user_stmt_, TRY_RESULT_ASSIGN(delete_dialog_messages_by_sender_stmt_,
db_.get_statement("DELETE FROM messages WHERE dialog_id = ?1 AND sender_user_id == ?2")); db_.get_statement("DELETE FROM messages WHERE dialog_id = ?1 AND sender_user_id == ?2"));
TRY_RESULT_ASSIGN( TRY_RESULT_ASSIGN(
@ -292,7 +292,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
return Status::OK(); return Status::OK();
} }
Status add_message(FullMessageId full_message_id, ServerMessageId unique_message_id, UserId sender_user_id, Status add_message(FullMessageId full_message_id, ServerMessageId unique_message_id, DialogId sender_dialog_id,
int64 random_id, int32 ttl_expires_at, int32 index_mask, int64 search_id, string text, int64 random_id, int32 ttl_expires_at, int32 index_mask, int64 search_id, string text,
NotificationId notification_id, MessageId top_thread_message_id, BufferSlice data) final { NotificationId notification_id, MessageId top_thread_message_id, BufferSlice data) final {
LOG(INFO) << "Add " << full_message_id << " to database"; LOG(INFO) << "Add " << full_message_id << " to database";
@ -312,8 +312,8 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
add_message_stmt_.bind_null(3).ensure(); add_message_stmt_.bind_null(3).ensure();
} }
if (sender_user_id.is_valid()) { if (sender_dialog_id.is_valid()) {
add_message_stmt_.bind_int64(4, sender_user_id.get()).ensure(); add_message_stmt_.bind_int64(4, sender_dialog_id.get()).ensure();
} else { } else {
add_message_stmt_.bind_null(4).ensure(); add_message_stmt_.bind_null(4).ensure();
} }
@ -438,16 +438,16 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
return status; return status;
} }
Status delete_dialog_messages_from_user(DialogId dialog_id, UserId sender_user_id) final { Status delete_dialog_messages_by_sender(DialogId dialog_id, DialogId sender_dialog_id) final {
LOG(INFO) << "Delete all messages in " << dialog_id << " sent by " << sender_user_id << " from database"; LOG(INFO) << "Delete all messages in " << dialog_id << " sent by " << sender_dialog_id << " from database";
CHECK(dialog_id.is_valid()); CHECK(dialog_id.is_valid());
CHECK(sender_user_id.is_valid()); CHECK(sender_dialog_id.is_valid());
SCOPE_EXIT { SCOPE_EXIT {
delete_dialog_messages_from_user_stmt_.reset(); delete_dialog_messages_by_sender_stmt_.reset();
}; };
delete_dialog_messages_from_user_stmt_.bind_int64(1, dialog_id.get()).ensure(); delete_dialog_messages_by_sender_stmt_.bind_int64(1, dialog_id.get()).ensure();
delete_dialog_messages_from_user_stmt_.bind_int64(2, sender_user_id.get()).ensure(); delete_dialog_messages_by_sender_stmt_.bind_int64(2, sender_dialog_id.get()).ensure();
delete_dialog_messages_from_user_stmt_.step().ensure(); delete_dialog_messages_by_sender_stmt_.step().ensure();
return Status::OK(); return Status::OK();
} }
@ -857,7 +857,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
SqliteStatement delete_message_stmt_; SqliteStatement delete_message_stmt_;
SqliteStatement delete_all_dialog_messages_stmt_; SqliteStatement delete_all_dialog_messages_stmt_;
SqliteStatement delete_dialog_messages_from_user_stmt_; SqliteStatement delete_dialog_messages_by_sender_stmt_;
SqliteStatement get_message_stmt_; SqliteStatement get_message_stmt_;
SqliteStatement get_message_by_random_id_stmt_; SqliteStatement get_message_by_random_id_stmt_;
@ -1017,11 +1017,11 @@ class MessagesDbAsync final : public MessagesDbAsyncInterface {
impl_ = create_actor_on_scheduler<Impl>("MessagesDbActor", scheduler_id, std::move(sync_db)); impl_ = create_actor_on_scheduler<Impl>("MessagesDbActor", scheduler_id, std::move(sync_db));
} }
void add_message(FullMessageId full_message_id, ServerMessageId unique_message_id, UserId sender_user_id, void add_message(FullMessageId full_message_id, ServerMessageId unique_message_id, DialogId sender_dialog_id,
int64 random_id, int32 ttl_expires_at, int32 index_mask, int64 search_id, string text, int64 random_id, int32 ttl_expires_at, int32 index_mask, int64 search_id, string text,
NotificationId notification_id, MessageId top_thread_message_id, BufferSlice data, NotificationId notification_id, MessageId top_thread_message_id, BufferSlice data,
Promise<> promise) final { Promise<> promise) final {
send_closure_later(impl_, &Impl::add_message, full_message_id, unique_message_id, sender_user_id, random_id, send_closure_later(impl_, &Impl::add_message, full_message_id, unique_message_id, sender_dialog_id, random_id,
ttl_expires_at, index_mask, search_id, std::move(text), notification_id, top_thread_message_id, ttl_expires_at, index_mask, search_id, std::move(text), notification_id, top_thread_message_id,
std::move(data), std::move(promise)); std::move(data), std::move(promise));
} }
@ -1035,8 +1035,8 @@ class MessagesDbAsync final : public MessagesDbAsyncInterface {
void delete_all_dialog_messages(DialogId dialog_id, MessageId from_message_id, Promise<> promise) final { void delete_all_dialog_messages(DialogId dialog_id, MessageId from_message_id, Promise<> promise) final {
send_closure_later(impl_, &Impl::delete_all_dialog_messages, dialog_id, from_message_id, std::move(promise)); send_closure_later(impl_, &Impl::delete_all_dialog_messages, dialog_id, from_message_id, std::move(promise));
} }
void delete_dialog_messages_from_user(DialogId dialog_id, UserId sender_user_id, Promise<> promise) final { void delete_dialog_messages_by_sender(DialogId dialog_id, DialogId sender_dialog_id, Promise<> promise) final {
send_closure_later(impl_, &Impl::delete_dialog_messages_from_user, dialog_id, sender_user_id, std::move(promise)); send_closure_later(impl_, &Impl::delete_dialog_messages_by_sender, dialog_id, sender_dialog_id, std::move(promise));
} }
void get_message(FullMessageId full_message_id, Promise<MessagesDbDialogMessage> promise) final { void get_message(FullMessageId full_message_id, Promise<MessagesDbDialogMessage> promise) final {
@ -1098,15 +1098,15 @@ class MessagesDbAsync final : public MessagesDbAsyncInterface {
public: public:
explicit Impl(std::shared_ptr<MessagesDbSyncSafeInterface> sync_db_safe) : sync_db_safe_(std::move(sync_db_safe)) { explicit Impl(std::shared_ptr<MessagesDbSyncSafeInterface> sync_db_safe) : sync_db_safe_(std::move(sync_db_safe)) {
} }
void add_message(FullMessageId full_message_id, ServerMessageId unique_message_id, UserId sender_user_id, void add_message(FullMessageId full_message_id, ServerMessageId unique_message_id, DialogId sender_dialog_id,
int64 random_id, int32 ttl_expires_at, int32 index_mask, int64 search_id, string text, int64 random_id, int32 ttl_expires_at, int32 index_mask, int64 search_id, string text,
NotificationId notification_id, MessageId top_thread_message_id, BufferSlice data, NotificationId notification_id, MessageId top_thread_message_id, BufferSlice data,
Promise<> promise) { Promise<> promise) {
add_write_query([this, full_message_id, unique_message_id, sender_user_id, random_id, ttl_expires_at, index_mask, add_write_query([this, full_message_id, unique_message_id, sender_dialog_id, random_id, ttl_expires_at,
search_id, text = std::move(text), notification_id, top_thread_message_id, index_mask, search_id, text = std::move(text), notification_id, top_thread_message_id,
data = std::move(data), promise = std::move(promise)](Unit) mutable { data = std::move(data), promise = std::move(promise)](Unit) mutable {
on_write_result(std::move(promise), on_write_result(std::move(promise),
sync_db_->add_message(full_message_id, unique_message_id, sender_user_id, random_id, sync_db_->add_message(full_message_id, unique_message_id, sender_dialog_id, random_id,
ttl_expires_at, index_mask, search_id, std::move(text), notification_id, ttl_expires_at, index_mask, search_id, std::move(text), notification_id,
top_thread_message_id, std::move(data))); top_thread_message_id, std::move(data)));
}); });
@ -1131,9 +1131,9 @@ class MessagesDbAsync final : public MessagesDbAsyncInterface {
add_read_query(); add_read_query();
promise.set_result(sync_db_->delete_all_dialog_messages(dialog_id, from_message_id)); promise.set_result(sync_db_->delete_all_dialog_messages(dialog_id, from_message_id));
} }
void delete_dialog_messages_from_user(DialogId dialog_id, UserId sender_user_id, Promise<> promise) { void delete_dialog_messages_by_sender(DialogId dialog_id, DialogId sender_dialog_id, Promise<> promise) {
add_read_query(); add_read_query();
promise.set_result(sync_db_->delete_dialog_messages_from_user(dialog_id, sender_user_id)); promise.set_result(sync_db_->delete_dialog_messages_by_sender(dialog_id, sender_dialog_id));
} }
void get_message(FullMessageId full_message_id, Promise<MessagesDbDialogMessage> promise) { void get_message(FullMessageId full_message_id, Promise<MessagesDbDialogMessage> promise) {

View File

@ -105,14 +105,15 @@ class MessagesDbSyncInterface {
MessagesDbSyncInterface &operator=(const MessagesDbSyncInterface &) = delete; MessagesDbSyncInterface &operator=(const MessagesDbSyncInterface &) = delete;
virtual ~MessagesDbSyncInterface() = default; virtual ~MessagesDbSyncInterface() = default;
virtual Status add_message(FullMessageId full_message_id, ServerMessageId unique_message_id, UserId sender_user_id, virtual Status add_message(FullMessageId full_message_id, ServerMessageId unique_message_id,
int64 random_id, int32 ttl_expires_at, int32 index_mask, int64 search_id, string text, DialogId sender_dialog_id, int64 random_id, int32 ttl_expires_at, int32 index_mask,
NotificationId notification_id, MessageId top_thread_message_id, BufferSlice data) = 0; int64 search_id, string text, NotificationId notification_id,
MessageId top_thread_message_id, BufferSlice data) = 0;
virtual Status add_scheduled_message(FullMessageId full_message_id, BufferSlice data) = 0; virtual Status add_scheduled_message(FullMessageId full_message_id, BufferSlice data) = 0;
virtual Status delete_message(FullMessageId full_message_id) = 0; virtual Status delete_message(FullMessageId full_message_id) = 0;
virtual Status delete_all_dialog_messages(DialogId dialog_id, MessageId from_message_id) = 0; virtual Status delete_all_dialog_messages(DialogId dialog_id, MessageId from_message_id) = 0;
virtual Status delete_dialog_messages_from_user(DialogId dialog_id, UserId sender_user_id) = 0; virtual Status delete_dialog_messages_by_sender(DialogId dialog_id, DialogId sender_dialog_id) = 0;
virtual Result<MessagesDbDialogMessage> get_message(FullMessageId full_message_id) = 0; virtual Result<MessagesDbDialogMessage> get_message(FullMessageId full_message_id) = 0;
virtual Result<MessagesDbMessage> get_message_by_unique_message_id(ServerMessageId unique_message_id) = 0; virtual Result<MessagesDbMessage> get_message_by_unique_message_id(ServerMessageId unique_message_id) = 0;
@ -158,7 +159,7 @@ class MessagesDbAsyncInterface {
MessagesDbAsyncInterface &operator=(const MessagesDbAsyncInterface &) = delete; MessagesDbAsyncInterface &operator=(const MessagesDbAsyncInterface &) = delete;
virtual ~MessagesDbAsyncInterface() = default; virtual ~MessagesDbAsyncInterface() = default;
virtual void add_message(FullMessageId full_message_id, ServerMessageId unique_message_id, UserId sender_user_id, virtual void add_message(FullMessageId full_message_id, ServerMessageId unique_message_id, DialogId sender_dialog_id,
int64 random_id, int32 ttl_expires_at, int32 index_mask, int64 search_id, string text, int64 random_id, int32 ttl_expires_at, int32 index_mask, int64 search_id, string text,
NotificationId notification_id, MessageId top_thread_message_id, BufferSlice data, NotificationId notification_id, MessageId top_thread_message_id, BufferSlice data,
Promise<> promise) = 0; Promise<> promise) = 0;
@ -166,7 +167,7 @@ class MessagesDbAsyncInterface {
virtual void delete_message(FullMessageId full_message_id, Promise<> promise) = 0; virtual void delete_message(FullMessageId full_message_id, Promise<> promise) = 0;
virtual void delete_all_dialog_messages(DialogId dialog_id, MessageId from_message_id, Promise<> promise) = 0; virtual void delete_all_dialog_messages(DialogId dialog_id, MessageId from_message_id, Promise<> promise) = 0;
virtual void delete_dialog_messages_from_user(DialogId dialog_id, UserId sender_user_id, Promise<> promise) = 0; virtual void delete_dialog_messages_by_sender(DialogId dialog_id, DialogId sender_dialog_id, Promise<> promise) = 0;
virtual void get_message(FullMessageId full_message_id, Promise<MessagesDbDialogMessage> promise) = 0; virtual void get_message(FullMessageId full_message_id, Promise<MessagesDbDialogMessage> promise) = 0;
virtual void get_message_by_unique_message_id(ServerMessageId unique_message_id, virtual void get_message_by_unique_message_id(ServerMessageId unique_message_id,

File diff suppressed because it is too large Load Diff

View File

@ -120,6 +120,7 @@ class MessagesManager final : public Actor {
static constexpr int32 MESSAGE_FLAG_HAS_REPLY_INFO = 1 << 23; static constexpr int32 MESSAGE_FLAG_HAS_REPLY_INFO = 1 << 23;
static constexpr int32 MESSAGE_FLAG_IS_PINNED = 1 << 24; static constexpr int32 MESSAGE_FLAG_IS_PINNED = 1 << 24;
static constexpr int32 MESSAGE_FLAG_HAS_TTL_PERIOD = 1 << 25; static constexpr int32 MESSAGE_FLAG_HAS_TTL_PERIOD = 1 << 25;
static constexpr int32 MESSAGE_FLAG_NOFORWARDS = 1 << 26;
static constexpr int32 SEND_MESSAGE_FLAG_IS_REPLY = 1 << 0; static constexpr int32 SEND_MESSAGE_FLAG_IS_REPLY = 1 << 0;
static constexpr int32 SEND_MESSAGE_FLAG_DISABLE_WEB_PAGE_PREVIEW = 1 << 1; static constexpr int32 SEND_MESSAGE_FLAG_DISABLE_WEB_PAGE_PREVIEW = 1 << 1;
@ -133,6 +134,7 @@ class MessagesManager final : public Actor {
static constexpr int32 SEND_MESSAGE_FLAG_GROUP_MEDIA = 1 << 9; static constexpr int32 SEND_MESSAGE_FLAG_GROUP_MEDIA = 1 << 9;
static constexpr int32 SEND_MESSAGE_FLAG_HAS_SCHEDULE_DATE = 1 << 10; static constexpr int32 SEND_MESSAGE_FLAG_HAS_SCHEDULE_DATE = 1 << 10;
static constexpr int32 SEND_MESSAGE_FLAG_HAS_MESSAGE = 1 << 11; static constexpr int32 SEND_MESSAGE_FLAG_HAS_MESSAGE = 1 << 11;
static constexpr int32 SEND_MESSAGE_FLAG_HAS_SEND_AS = 1 << 13;
static constexpr int32 ONLINE_MEMBER_COUNT_CACHE_EXPIRE_TIME = 30 * 60; static constexpr int32 ONLINE_MEMBER_COUNT_CACHE_EXPIRE_TIME = 30 * 60;
@ -307,6 +309,9 @@ class MessagesManager final : public Actor {
void on_update_dialog_default_join_group_call_as_dialog_id(DialogId dialog_id, DialogId default_join_as_dialog_id, void on_update_dialog_default_join_group_call_as_dialog_id(DialogId dialog_id, DialogId default_join_as_dialog_id,
bool force); bool force);
void on_update_dialog_default_send_message_as_dialog_id(DialogId dialog_id, DialogId default_send_as_dialog_id,
bool force);
void on_update_dialog_message_ttl_setting(DialogId dialog_id, MessageTtlSetting message_ttl_setting); void on_update_dialog_message_ttl_setting(DialogId dialog_id, MessageTtlSetting message_ttl_setting);
void on_update_dialog_filters(); void on_update_dialog_filters();
@ -351,7 +356,9 @@ class MessagesManager final : public Actor {
void on_update_delete_scheduled_messages(DialogId dialog_id, vector<ScheduledServerMessageId> &&server_message_ids); void on_update_delete_scheduled_messages(DialogId dialog_id, vector<ScheduledServerMessageId> &&server_message_ids);
void on_user_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, DialogId typing_dialog_id, void on_update_created_public_broadcasts(vector<ChannelId> channel_ids);
void on_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, DialogId typing_dialog_id,
DialogAction action, int32 date, DialogAction action, int32 date,
MessageContentType message_content_type = MessageContentType::None); MessageContentType message_content_type = MessageContentType::None);
@ -363,7 +370,7 @@ class MessagesManager final : public Actor {
void delete_all_call_messages(bool revoke, Promise<Unit> &&promise); void delete_all_call_messages(bool revoke, Promise<Unit> &&promise);
void delete_dialog_messages_from_user(DialogId dialog_id, UserId user_id, Promise<Unit> &&promise); void delete_dialog_messages_by_sender(DialogId dialog_id, DialogId sender_dialog_id, Promise<Unit> &&promise);
void delete_dialog_messages_by_date(DialogId dialog_id, int32 min_date, int32 max_date, bool revoke, void delete_dialog_messages_by_date(DialogId dialog_id, int32 min_date, int32 max_date, bool revoke,
Promise<Unit> &&promise); Promise<Unit> &&promise);
@ -388,6 +395,13 @@ class MessagesManager final : public Actor {
void reload_voice_chat_on_search(const string &username); void reload_voice_chat_on_search(const string &username);
void get_dialog_send_message_as_dialog_ids(DialogId dialog_id,
Promise<td_api::object_ptr<td_api::messageSenders>> &&promise,
bool is_recursive = false);
void set_dialog_default_send_message_as_dialog_id(DialogId dialog_id, DialogId message_sender_dialog_id,
Promise<Unit> &&promise);
Result<td_api::object_ptr<td_api::message>> send_message( Result<td_api::object_ptr<td_api::message>> send_message(
DialogId dialog_id, MessageId top_thread_message_id, MessageId reply_to_message_id, DialogId dialog_id, MessageId top_thread_message_id, MessageId reply_to_message_id,
tl_object_ptr<td_api::messageSendOptions> &&options, tl_object_ptr<td_api::ReplyMarkup> &&reply_markup, tl_object_ptr<td_api::messageSendOptions> &&options, tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
@ -494,6 +508,8 @@ class MessagesManager final : public Actor {
void set_dialog_permissions(DialogId dialog_id, const td_api::object_ptr<td_api::chatPermissions> &permissions, void set_dialog_permissions(DialogId dialog_id, const td_api::object_ptr<td_api::chatPermissions> &permissions,
Promise<Unit> &&promise); Promise<Unit> &&promise);
void toggle_dialog_has_protected_content(DialogId dialog_id, bool has_protected_content, Promise<Unit> &&promise);
void set_dialog_theme(DialogId dialog_id, const string &theme_name, Promise<Unit> &&promise); void set_dialog_theme(DialogId dialog_id, const string &theme_name, Promise<Unit> &&promise);
void pin_dialog_message(DialogId dialog_id, MessageId message_id, bool disable_notification, bool only_for_self, void pin_dialog_message(DialogId dialog_id, MessageId message_id, bool disable_notification, bool only_for_self,
@ -513,6 +529,8 @@ class MessagesManager final : public Actor {
void reload_dialog_info_full(DialogId dialog_id); void reload_dialog_info_full(DialogId dialog_id);
void on_dialog_info_full_invalidated(DialogId dialog_id);
bool load_dialog(DialogId dialog_id, int left_tries, Promise<Unit> &&promise); bool load_dialog(DialogId dialog_id, int left_tries, Promise<Unit> &&promise);
void load_dialogs(vector<DialogId> dialog_ids, Promise<vector<DialogId>> &&promise); void load_dialogs(vector<DialogId> dialog_ids, Promise<vector<DialogId>> &&promise);
@ -551,6 +569,8 @@ class MessagesManager final : public Actor {
bool can_get_message_statistics(FullMessageId full_message_id); bool can_get_message_statistics(FullMessageId full_message_id);
DialogId get_message_sender(FullMessageId full_message_id);
bool have_message_force(FullMessageId full_message_id, const char *source); bool have_message_force(FullMessageId full_message_id, const char *source);
void get_message(FullMessageId full_message_id, Promise<Unit> &&promise); void get_message(FullMessageId full_message_id, Promise<Unit> &&promise);
@ -638,6 +658,8 @@ class MessagesManager final : public Actor {
DialogId migrate_dialog_to_megagroup(DialogId dialog_id, Promise<Unit> &&promise); DialogId migrate_dialog_to_megagroup(DialogId dialog_id, Promise<Unit> &&promise);
bool is_dialog_opened(DialogId dialog_id) const;
Status open_dialog(DialogId dialog_id) TD_WARN_UNUSED_RESULT; Status open_dialog(DialogId dialog_id) TD_WARN_UNUSED_RESULT;
Status close_dialog(DialogId dialog_id) TD_WARN_UNUSED_RESULT; Status close_dialog(DialogId dialog_id) TD_WARN_UNUSED_RESULT;
@ -781,7 +803,8 @@ class MessagesManager final : public Actor {
void on_dialog_photo_updated(DialogId dialog_id); void on_dialog_photo_updated(DialogId dialog_id);
void on_dialog_title_updated(DialogId dialog_id); void on_dialog_title_updated(DialogId dialog_id);
void on_dialog_username_updated(DialogId dialog_id, const string &old_username, const string &new_username); void on_dialog_username_updated(DialogId dialog_id, const string &old_username, const string &new_username);
void on_dialog_permissions_updated(DialogId dialog_id); void on_dialog_default_permissions_updated(DialogId dialog_id);
void on_dialog_has_protected_content_updated(DialogId dialog_id);
void on_dialog_user_is_contact_updated(DialogId dialog_id, bool is_contact); void on_dialog_user_is_contact_updated(DialogId dialog_id, bool is_contact);
void on_dialog_user_is_deleted_updated(DialogId dialog_id, bool is_deleted); void on_dialog_user_is_deleted_updated(DialogId dialog_id, bool is_deleted);
@ -1068,7 +1091,9 @@ class MessagesManager final : public Actor {
bool is_from_scheduled = false; bool is_from_scheduled = false;
bool is_pinned = false; bool is_pinned = false;
bool are_media_timestamp_entities_found = false; bool are_media_timestamp_entities_found = false;
bool noforwards = false;
bool has_explicit_sender = false; // for send_message
bool is_copy = false; // for send_message bool is_copy = false; // for send_message
bool from_background = false; // for send_message bool from_background = false; // for send_message
bool disable_web_page_preview = false; // for send_message bool disable_web_page_preview = false; // for send_message
@ -1193,6 +1218,7 @@ class MessagesManager final : public Actor {
InputGroupCallId active_group_call_id; InputGroupCallId active_group_call_id;
InputGroupCallId expected_active_group_call_id; InputGroupCallId expected_active_group_call_id;
DialogId default_join_group_call_as_dialog_id; DialogId default_join_group_call_as_dialog_id;
DialogId default_send_message_as_dialog_id;
string theme_name; string theme_name;
int32 pending_join_request_count = 0; int32 pending_join_request_count = 0;
vector<UserId> pending_join_request_user_ids; vector<UserId> pending_join_request_user_ids;
@ -1636,7 +1662,7 @@ class MessagesManager final : public Actor {
class BlockMessageSenderFromRepliesOnServerLogEvent; class BlockMessageSenderFromRepliesOnServerLogEvent;
class DeleteAllCallMessagesOnServerLogEvent; class DeleteAllCallMessagesOnServerLogEvent;
class DeleteAllChannelMessagesFromUserOnServerLogEvent; class DeleteAllChannelMessagesFromSenderOnServerLogEvent;
class DeleteDialogHistoryOnServerLogEvent; class DeleteDialogHistoryOnServerLogEvent;
class DeleteDialogMessagesByDateOnServerLogEvent; class DeleteDialogMessagesByDateOnServerLogEvent;
class DeleteMessageLogEvent; class DeleteMessageLogEvent;
@ -1796,12 +1822,13 @@ class MessagesManager final : public Actor {
unique_ptr<Message> create_message_to_send(Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id, unique_ptr<Message> create_message_to_send(Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id,
const MessageSendOptions &options, unique_ptr<MessageContent> &&content, const MessageSendOptions &options, unique_ptr<MessageContent> &&content,
bool suppress_reply_info, unique_ptr<MessageForwardInfo> forward_info, bool suppress_reply_info, unique_ptr<MessageForwardInfo> forward_info,
bool is_copy) const; bool is_copy, DialogId send_as_dialog_id) const;
Message *get_message_to_send(Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id, Message *get_message_to_send(Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id,
const MessageSendOptions &options, unique_ptr<MessageContent> &&content, const MessageSendOptions &options, unique_ptr<MessageContent> &&content,
bool *need_update_dialog_pos, bool suppress_reply_info = false, bool *need_update_dialog_pos, bool suppress_reply_info = false,
unique_ptr<MessageForwardInfo> forward_info = nullptr, bool is_copy = false); unique_ptr<MessageForwardInfo> forward_info = nullptr, bool is_copy = false,
DialogId sender_dialog_id = DialogId());
int64 begin_send_message(DialogId dialog_id, const Message *m); int64 begin_send_message(DialogId dialog_id, const Message *m);
@ -1951,6 +1978,8 @@ class MessagesManager final : public Actor {
static bool can_forward_message(DialogId from_dialog_id, const Message *m); static bool can_forward_message(DialogId from_dialog_id, const Message *m);
bool can_save_message(DialogId dialog_id, const Message *m) const;
bool can_get_message_statistics(DialogId dialog_id, const Message *m) const; bool can_get_message_statistics(DialogId dialog_id, const Message *m) const;
static bool can_delete_channel_message(const DialogParticipantStatus &status, const Message *m, bool is_bot); static bool can_delete_channel_message(const DialogParticipantStatus &status, const Message *m, bool is_bot);
@ -2002,8 +2031,8 @@ class MessagesManager final : public Actor {
bool need_delete_all_messages, bool report_spam, uint64 log_event_id, bool need_delete_all_messages, bool report_spam, uint64 log_event_id,
Promise<Unit> &&promise); Promise<Unit> &&promise);
void delete_all_channel_messages_from_user_on_server(ChannelId channel_id, UserId user_id, uint64 log_event_id, void delete_all_channel_messages_by_sender_on_server(ChannelId channel_id, DialogId sender_dialog_id,
Promise<Unit> &&promise); uint64 log_event_id, Promise<Unit> &&promise);
void delete_dialog_messages_by_date_on_server(DialogId dialog_id, int32 min_date, int32 max_date, bool revoke, void delete_dialog_messages_by_date_on_server(DialogId dialog_id, int32 min_date, int32 max_date, bool revoke,
uint64 log_event_id, Promise<Unit> &&promise); uint64 log_event_id, Promise<Unit> &&promise);
@ -2368,11 +2397,13 @@ class MessagesManager final : public Actor {
void send_update_chat_video_chat(const Dialog *d); void send_update_chat_video_chat(const Dialog *d);
void send_update_chat_default_message_sender_id(const Dialog *d);
void send_update_chat_message_ttl_setting(const Dialog *d); void send_update_chat_message_ttl_setting(const Dialog *d);
void send_update_chat_has_scheduled_messages(Dialog *d, bool from_deletion); void send_update_chat_has_scheduled_messages(Dialog *d, bool from_deletion);
void send_update_user_chat_action(DialogId dialog_id, MessageId top_thread_message_id, UserId user_id, void send_update_chat_action(DialogId dialog_id, MessageId top_thread_message_id, DialogId typing_dialog_id,
const DialogAction &action); const DialogAction &action);
void repair_dialog_action_bar(Dialog *d, const char *source); void repair_dialog_action_bar(Dialog *d, const char *source);
@ -2538,7 +2569,7 @@ class MessagesManager final : public Actor {
void clear_active_dialog_actions(DialogId dialog_id); void clear_active_dialog_actions(DialogId dialog_id);
void cancel_user_dialog_action(DialogId dialog_id, const Message *m); void cancel_dialog_action(DialogId dialog_id, const Message *m);
Dialog *get_dialog_by_message_id(MessageId message_id); Dialog *get_dialog_by_message_id(MessageId message_id);
@ -2550,7 +2581,8 @@ class MessagesManager final : public Actor {
void fix_new_dialog(Dialog *d, unique_ptr<Message> &&last_database_message, MessageId last_database_message_id, void fix_new_dialog(Dialog *d, unique_ptr<Message> &&last_database_message, MessageId last_database_message_id,
int64 order, int32 last_clear_history_date, MessageId last_clear_history_message_id, int64 order, int32 last_clear_history_date, MessageId last_clear_history_message_id,
DialogId default_join_group_call_as_dialog_id, bool is_loaded_from_database); DialogId default_join_group_call_as_dialog_id, DialogId default_send_message_as_dialog_id,
bool is_loaded_from_database);
void add_dialog_last_database_message(Dialog *d, unique_ptr<Message> &&last_database_message); void add_dialog_last_database_message(Dialog *d, unique_ptr<Message> &&last_database_message);
@ -2566,6 +2598,8 @@ class MessagesManager final : public Actor {
td_api::object_ptr<td_api::videoChat> get_video_chat_object(const Dialog *d) const; td_api::object_ptr<td_api::videoChat> get_video_chat_object(const Dialog *d) const;
td_api::object_ptr<td_api::MessageSender> get_default_sender_id_object(const Dialog *d) const;
td_api::object_ptr<td_api::chat> get_chat_object(const Dialog *d) const; td_api::object_ptr<td_api::chat> get_chat_object(const Dialog *d) const;
Dialog *get_dialog(DialogId dialog_id); Dialog *get_dialog(DialogId dialog_id);
@ -2754,6 +2788,8 @@ class MessagesManager final : public Actor {
static int32 get_message_flags(const Message *m); static int32 get_message_flags(const Message *m);
tl_object_ptr<telegram_api::InputPeer> get_send_message_as_input_peer(const Message *m) const;
static bool is_forward_info_sender_hidden(const MessageForwardInfo *forward_info); static bool is_forward_info_sender_hidden(const MessageForwardInfo *forward_info);
unique_ptr<MessageForwardInfo> get_message_forward_info( unique_ptr<MessageForwardInfo> get_message_forward_info(
@ -2866,6 +2902,8 @@ class MessagesManager final : public Actor {
RestrictedRights get_dialog_default_permissions(DialogId dialog_id) const; RestrictedRights get_dialog_default_permissions(DialogId dialog_id) const;
bool get_dialog_has_protected_content(DialogId dialog_id) const;
bool get_dialog_has_scheduled_messages(const Dialog *d) const; bool get_dialog_has_scheduled_messages(const Dialog *d) const;
static int64 get_dialog_order(MessageId message_id, int32 message_date); static int64 get_dialog_order(MessageId message_id, int32 message_date);
@ -3020,8 +3058,6 @@ class MessagesManager final : public Actor {
void send_get_message_public_forwards_query(DcId dc_id, FullMessageId full_message_id, string offset, int32 limit, void send_get_message_public_forwards_query(DcId dc_id, FullMessageId full_message_id, string offset, int32 limit,
Promise<td_api::object_ptr<td_api::foundMessages>> &&promise); Promise<td_api::object_ptr<td_api::foundMessages>> &&promise);
void on_animated_emoji_message_clicked(FullMessageId full_message_id, UserId user_id, Slice emoji, string data);
void add_sponsored_dialog(const Dialog *d, DialogSource source); void add_sponsored_dialog(const Dialog *d, DialogSource source);
void save_sponsored_dialog(); void save_sponsored_dialog();
@ -3096,7 +3132,8 @@ class MessagesManager final : public Actor {
bool need_delete_all_messages, bool need_delete_all_messages,
bool report_spam); bool report_spam);
static uint64 save_delete_all_channel_messages_from_user_on_server_log_event(ChannelId channel_id, UserId user_id); static uint64 save_delete_all_channel_messages_by_sender_on_server_log_event(ChannelId channel_id,
DialogId sender_dialog_id);
static uint64 save_delete_dialog_messages_by_date_on_server_log_event(DialogId dialog_id, int32 min_date, static uint64 save_delete_dialog_messages_by_date_on_server_log_event(DialogId dialog_id, int32 min_date,
int32 max_date, bool revoke); int32 max_date, bool revoke);
@ -3144,6 +3181,8 @@ class MessagesManager final : public Actor {
static DialogId get_message_original_sender(const Message *m); static DialogId get_message_original_sender(const Message *m);
static DialogId get_message_sender(const Message *m);
RecentDialogList recently_found_dialogs_; RecentDialogList recently_found_dialogs_;
RecentDialogList recently_opened_dialogs_; RecentDialogList recently_opened_dialogs_;
@ -3291,6 +3330,9 @@ class MessagesManager final : public Actor {
std::unordered_map<MessageId, DialogId, MessageIdHash> message_id_to_dialog_id_; std::unordered_map<MessageId, DialogId, MessageIdHash> message_id_to_dialog_id_;
std::unordered_map<MessageId, DialogId, MessageIdHash> last_clear_history_message_id_to_dialog_id_; std::unordered_map<MessageId, DialogId, MessageIdHash> last_clear_history_message_id_to_dialog_id_;
bool created_public_broadcasts_inited_ = false;
vector<ChannelId> created_public_broadcasts_;
std::unordered_map<int64, DialogId> created_dialogs_; // random_id -> dialog_id std::unordered_map<int64, DialogId> created_dialogs_; // random_id -> dialog_id
std::unordered_map<DialogId, Promise<Unit>, DialogIdHash> pending_created_dialogs_; // dialog_id -> promise std::unordered_map<DialogId, Promise<Unit>, DialogIdHash> pending_created_dialogs_; // dialog_id -> promise
@ -3357,13 +3399,14 @@ class MessagesManager final : public Actor {
struct ActiveDialogAction { struct ActiveDialogAction {
MessageId top_thread_message_id; MessageId top_thread_message_id;
UserId user_id; DialogId typing_dialog_id;
DialogAction action; DialogAction action;
double start_time; double start_time;
ActiveDialogAction(MessageId top_thread_message_id, UserId user_id, DialogAction action, double start_time) ActiveDialogAction(MessageId top_thread_message_id, DialogId typing_dialog_id, DialogAction action,
double start_time)
: top_thread_message_id(top_thread_message_id) : top_thread_message_id(top_thread_message_id)
, user_id(user_id) , typing_dialog_id(typing_dialog_id)
, action(std::move(action)) , action(std::move(action))
, start_time(start_time) { , start_time(start_time) {
} }
@ -3471,6 +3514,9 @@ class MessagesManager final : public Actor {
std::unordered_map<DialogId, vector<DialogId>, DialogIdHash> std::unordered_map<DialogId, vector<DialogId>, DialogIdHash>
pending_add_default_join_group_call_as_dialog_id_; // dialog_id -> dependent dialogs pending_add_default_join_group_call_as_dialog_id_; // dialog_id -> dependent dialogs
std::unordered_map<DialogId, vector<DialogId>, DialogIdHash>
pending_add_default_send_message_as_dialog_id_; // dialog_id -> dependent dialogs
struct MessageIds { struct MessageIds {
std::unordered_set<MessageId, MessageIdHash> message_ids; std::unordered_set<MessageId, MessageIdHash> message_ids;
}; };

View File

@ -7,6 +7,7 @@
#include "td/telegram/PasswordManager.h" #include "td/telegram/PasswordManager.h"
#include "td/telegram/ConfigManager.h" #include "td/telegram/ConfigManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/DhCache.h" #include "td/telegram/DhCache.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/logevent/LogEvent.h" #include "td/telegram/logevent/LogEvent.h"
@ -747,6 +748,8 @@ void PasswordManager::do_get_state(Promise<PasswordState> promise) {
send_with_promise( send_with_promise(
std::move(query), PromiseCreator::lambda([actor_id = actor_id(this), code_length = last_code_length_, std::move(query), PromiseCreator::lambda([actor_id = actor_id(this), code_length = last_code_length_,
promise = std::move(promise)](Result<NetQueryPtr> r_query) mutable { promise = std::move(promise)](Result<NetQueryPtr> r_query) mutable {
TRY_STATUS_PROMISE(promise, G()->close_status());
auto r_result = fetch_result<telegram_api::account_getPassword>(std::move(r_query)); auto r_result = fetch_result<telegram_api::account_getPassword>(std::move(r_query));
if (r_result.is_error()) { if (r_result.is_error()) {
return promise.set_error(r_result.move_as_error()); return promise.set_error(r_result.move_as_error());
@ -780,6 +783,12 @@ void PasswordManager::do_get_state(Promise<PasswordState> promise) {
state.password_hint = std::move(password->hint_); state.password_hint = std::move(password->hint_);
state.has_recovery_email_address = password->has_recovery_; state.has_recovery_email_address = password->has_recovery_;
state.has_secure_values = password->has_secure_values_; state.has_secure_values = password->has_secure_values_;
auto days = narrow_cast<int32>(G()->shared_config().get_option_integer("otherwise_relogin_days"));
if (days > 0) {
dismiss_suggested_action(SuggestedAction{SuggestedAction::Type::SetPassword, DialogId(), days},
Promise<Unit>());
}
} else { } else {
state.has_password = false; state.has_password = false;
send_closure(actor_id, &PasswordManager::drop_cached_secret); send_closure(actor_id, &PasswordManager::drop_cached_secret);

View File

@ -7,6 +7,7 @@
#include "td/telegram/ReplyMarkup.h" #include "td/telegram/ReplyMarkup.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/Dependencies.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/LinkManager.h" #include "td/telegram/LinkManager.h"
#include "td/telegram/misc.h" #include "td/telegram/misc.h"
@ -90,6 +91,9 @@ static StringBuilder &operator<<(StringBuilder &string_builder, const InlineKeyb
case InlineKeyboardButton::Type::CallbackWithPassword: case InlineKeyboardButton::Type::CallbackWithPassword:
string_builder << "CallbackWithPassword"; string_builder << "CallbackWithPassword";
break; break;
case InlineKeyboardButton::Type::User:
string_builder << "User " << keyboard_button.user_id.get();
break;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
@ -264,9 +268,14 @@ static InlineKeyboardButton get_inline_keyboard_button(
button.id = keyboard_button->button_id_; button.id = keyboard_button->button_id_;
button.text = std::move(keyboard_button->text_); button.text = std::move(keyboard_button->text_);
button.data = std::move(keyboard_button->url_); button.data = std::move(keyboard_button->url_);
if ((keyboard_button->flags_ & telegram_api::keyboardButtonUrlAuth::FWD_TEXT_MASK) != 0) {
button.forward_text = std::move(keyboard_button->fwd_text_); button.forward_text = std::move(keyboard_button->fwd_text_);
break;
} }
case telegram_api::keyboardButtonUserProfile::ID: {
auto keyboard_button = move_tl_object_as<telegram_api::keyboardButtonUserProfile>(keyboard_button_ptr);
button.type = InlineKeyboardButton::Type::User;
button.text = std::move(keyboard_button->text_);
button.user_id = UserId(keyboard_button->user_id_);
break; break;
} }
default: default:
@ -434,42 +443,48 @@ static Result<InlineKeyboardButton> get_inline_keyboard_button(tl_object_ptr<td_
int32 button_type_id = button->type_->get_id(); int32 button_type_id = button->type_->get_id();
switch (button_type_id) { switch (button_type_id) {
case td_api::inlineKeyboardButtonTypeUrl::ID: { case td_api::inlineKeyboardButtonTypeUrl::ID: {
current_button.type = InlineKeyboardButton::Type::Url; auto button_type = move_tl_object_as<td_api::inlineKeyboardButtonTypeUrl>(button->type_);
auto r_url = auto user_id = LinkManager::get_link_user_id(button_type->url_);
LinkManager::check_link(static_cast<const td_api::inlineKeyboardButtonTypeUrl *>(button->type_.get())->url_); if (user_id.is_valid()) {
current_button.type = InlineKeyboardButton::Type::User;
current_button.user_id = user_id;
break;
}
auto r_url = LinkManager::check_link(button_type->url_);
if (r_url.is_error()) { if (r_url.is_error()) {
return Status::Error(400, "Inline keyboard button URL is invalid"); return Status::Error(400, "Inline keyboard button URL is invalid");
} }
current_button.type = InlineKeyboardButton::Type::Url;
current_button.data = r_url.move_as_ok(); current_button.data = r_url.move_as_ok();
if (!clean_input_string(current_button.data)) { if (!clean_input_string(current_button.data)) {
return Status::Error(400, "Inline keyboard button URL must be encoded in UTF-8"); return Status::Error(400, "Inline keyboard button URL must be encoded in UTF-8");
} }
break; break;
} }
case td_api::inlineKeyboardButtonTypeCallback::ID: case td_api::inlineKeyboardButtonTypeCallback::ID: {
auto button_type = move_tl_object_as<td_api::inlineKeyboardButtonTypeCallback>(button->type_);
current_button.type = InlineKeyboardButton::Type::Callback; current_button.type = InlineKeyboardButton::Type::Callback;
current_button.data = current_button.data = std::move(button_type->data_);
std::move(static_cast<td_api::inlineKeyboardButtonTypeCallback *>(button->type_.get())->data_);
break; break;
}
case td_api::inlineKeyboardButtonTypeCallbackGame::ID: case td_api::inlineKeyboardButtonTypeCallbackGame::ID:
current_button.type = InlineKeyboardButton::Type::CallbackGame; current_button.type = InlineKeyboardButton::Type::CallbackGame;
break; break;
case td_api::inlineKeyboardButtonTypeCallbackWithPassword::ID: case td_api::inlineKeyboardButtonTypeCallbackWithPassword::ID:
return Status::Error(400, "Can't use CallbackWithPassword inline button"); return Status::Error(400, "Can't use CallbackWithPassword inline button");
case td_api::inlineKeyboardButtonTypeSwitchInline::ID: { case td_api::inlineKeyboardButtonTypeSwitchInline::ID: {
auto switch_inline_button = move_tl_object_as<td_api::inlineKeyboardButtonTypeSwitchInline>(button->type_); auto button_type = move_tl_object_as<td_api::inlineKeyboardButtonTypeSwitchInline>(button->type_);
if (!switch_inline_buttons_allowed) { if (!switch_inline_buttons_allowed) {
const char *button_name = const char *button_name =
switch_inline_button->in_current_chat_ ? "switch_inline_query_current_chat" : "switch_inline_query"; button_type->in_current_chat_ ? "switch_inline_query_current_chat" : "switch_inline_query";
return Status::Error(400, PSLICE() << "Can't use " << button_name return Status::Error(400, PSLICE() << "Can't use " << button_name
<< " in a channel chat, because a user will not be able to use the button " << " in a channel chat, because a user will not be able to use the button "
"without knowing bot's username"); "without knowing bot's username");
} }
current_button.type = switch_inline_button->in_current_chat_ current_button.type = button_type->in_current_chat_ ? InlineKeyboardButton::Type::SwitchInlineCurrentDialog
? InlineKeyboardButton::Type::SwitchInlineCurrentDialog
: InlineKeyboardButton::Type::SwitchInline; : InlineKeyboardButton::Type::SwitchInline;
current_button.data = std::move(switch_inline_button->query_); current_button.data = std::move(button_type->query_);
if (!clean_input_string(current_button.data)) { if (!clean_input_string(current_button.data)) {
return Status::Error(400, "Inline keyboard button switch inline query must be encoded in UTF-8"); return Status::Error(400, "Inline keyboard button switch inline query must be encoded in UTF-8");
} }
@ -479,26 +494,40 @@ static Result<InlineKeyboardButton> get_inline_keyboard_button(tl_object_ptr<td_
current_button.type = InlineKeyboardButton::Type::Buy; current_button.type = InlineKeyboardButton::Type::Buy;
break; break;
case td_api::inlineKeyboardButtonTypeLoginUrl::ID: { case td_api::inlineKeyboardButtonTypeLoginUrl::ID: {
current_button.type = InlineKeyboardButton::Type::UrlAuth; auto button_type = td_api::move_object_as<td_api::inlineKeyboardButtonTypeLoginUrl>(button->type_);
auto login_url = td_api::move_object_as<td_api::inlineKeyboardButtonTypeLoginUrl>(button->type_); auto user_id = LinkManager::get_link_user_id(button_type->url_);
auto r_url = LinkManager::check_link(login_url->url_); if (user_id.is_valid()) {
return Status::Error(400, "Link to a user can't be used in login URL buttons");
}
auto r_url = LinkManager::check_link(button_type->url_);
if (r_url.is_error()) { if (r_url.is_error()) {
return Status::Error(400, "Inline keyboard button login URL is invalid"); return Status::Error(400, "Inline keyboard button login URL is invalid");
} }
current_button.type = InlineKeyboardButton::Type::UrlAuth;
current_button.data = r_url.move_as_ok(); current_button.data = r_url.move_as_ok();
current_button.forward_text = std::move(login_url->forward_text_); current_button.forward_text = std::move(button_type->forward_text_);
if (!clean_input_string(current_button.data)) { if (!clean_input_string(current_button.data)) {
return Status::Error(400, "Inline keyboard button login URL must be encoded in UTF-8"); return Status::Error(400, "Inline keyboard button login URL must be encoded in UTF-8");
} }
if (!clean_input_string(current_button.forward_text)) { if (!clean_input_string(current_button.forward_text)) {
return Status::Error(400, "Inline keyboard button forward text must be encoded in UTF-8"); return Status::Error(400, "Inline keyboard button forward text must be encoded in UTF-8");
} }
current_button.id = login_url->id_; current_button.id = button_type->id_;
if (current_button.id == 0 || current_button.id == std::numeric_limits<int64>::min()) { if (current_button.id == std::numeric_limits<int64>::min() ||
!UserId(current_button.id >= 0 ? current_button.id : -current_button.id).is_valid()) {
return Status::Error(400, "Invalid bot_user_id specified"); return Status::Error(400, "Invalid bot_user_id specified");
} }
break; break;
} }
case td_api::inlineKeyboardButtonTypeUser::ID: {
auto button_type = td_api::move_object_as<td_api::inlineKeyboardButtonTypeUser>(button->type_);
current_button.type = InlineKeyboardButton::Type::User;
current_button.user_id = UserId(button_type->user_id_);
if (!current_button.user_id.is_valid()) {
return Status::Error(400, "Invalid user_id specified");
}
break;
}
default: default:
UNREACHABLE(); UNREACHABLE();
} }
@ -683,6 +712,14 @@ static tl_object_ptr<telegram_api::KeyboardButton> get_inline_keyboard_button(
case InlineKeyboardButton::Type::CallbackWithPassword: case InlineKeyboardButton::Type::CallbackWithPassword:
UNREACHABLE(); UNREACHABLE();
break; break;
case InlineKeyboardButton::Type::User: {
auto input_user = G()->td().get_actor_unsafe()->contacts_manager_->get_input_user(keyboard_button.user_id);
if (input_user == nullptr) {
LOG(ERROR) << "Failed to get InputUser for " << keyboard_button.user_id;
input_user = make_tl_object<telegram_api::inputUserEmpty>();
}
return make_tl_object<telegram_api::inputKeyboardButtonUserProfile>(keyboard_button.text, std::move(input_user));
}
default: default:
UNREACHABLE(); UNREACHABLE();
return nullptr; return nullptr;
@ -796,6 +833,11 @@ static tl_object_ptr<td_api::inlineKeyboardButton> get_inline_keyboard_button_ob
case InlineKeyboardButton::Type::CallbackWithPassword: case InlineKeyboardButton::Type::CallbackWithPassword:
type = make_tl_object<td_api::inlineKeyboardButtonTypeCallbackWithPassword>(keyboard_button.data); type = make_tl_object<td_api::inlineKeyboardButtonTypeCallbackWithPassword>(keyboard_button.data);
break; break;
case InlineKeyboardButton::Type::User:
type = make_tl_object<td_api::inlineKeyboardButtonTypeUser>(
G()->td().get_actor_unsafe()->contacts_manager_->get_user_id_object(keyboard_button.user_id,
"get_inline_keyboard_button_object"));
break;
default: default:
UNREACHABLE(); UNREACHABLE();
return nullptr; return nullptr;
@ -860,4 +902,17 @@ tl_object_ptr<td_api::ReplyMarkup> get_reply_markup_object(const unique_ptr<Repl
return reply_markup->get_reply_markup_object(); return reply_markup->get_reply_markup_object();
} }
void add_reply_markup_dependencies(Dependencies &dependencies, const ReplyMarkup *reply_markup) {
if (reply_markup == nullptr) {
return;
}
for (auto &row : reply_markup->inline_keyboard) {
for (auto &button : row) {
if (button.user_id.is_valid()) {
dependencies.user_ids.insert(button.user_id);
}
}
}
}
} // namespace td } // namespace td

View File

@ -8,6 +8,7 @@
#include "td/telegram/td_api.h" #include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h" #include "td/telegram/telegram_api.h"
#include "td/telegram/UserId.h"
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/Status.h" #include "td/utils/Status.h"
@ -15,6 +16,8 @@
namespace td { namespace td {
struct Dependencies;
struct KeyboardButton { struct KeyboardButton {
// append only // append only
enum class Type : int32 { enum class Type : int32 {
@ -39,10 +42,12 @@ struct InlineKeyboardButton {
SwitchInlineCurrentDialog, SwitchInlineCurrentDialog,
Buy, Buy,
UrlAuth, UrlAuth,
CallbackWithPassword CallbackWithPassword,
User
}; };
Type type; Type type;
int64 id = 0; // UrlAuth only, button_id or (2 * request_write_access - 1) * bot_user_id int64 id = 0; // UrlAuth only, button_id or (2 * request_write_access - 1) * bot_user_id
UserId user_id; // User only
string text; string text;
string forward_text; // UrlAuth only string forward_text; // UrlAuth only
string data; string data;
@ -85,4 +90,6 @@ tl_object_ptr<telegram_api::ReplyMarkup> get_input_reply_markup(const unique_ptr
tl_object_ptr<td_api::ReplyMarkup> get_reply_markup_object(const unique_ptr<ReplyMarkup> &reply_markup); tl_object_ptr<td_api::ReplyMarkup> get_reply_markup_object(const unique_ptr<ReplyMarkup> &reply_markup);
void add_reply_markup_dependencies(Dependencies &dependencies, const ReplyMarkup *reply_markup);
} // namespace td } // namespace td

View File

@ -15,28 +15,78 @@ namespace td {
template <class StorerT> template <class StorerT>
void store(KeyboardButton button, StorerT &storer) { void store(KeyboardButton button, StorerT &storer) {
BEGIN_STORE_FLAGS();
END_STORE_FLAGS();
store(button.type, storer); store(button.type, storer);
store(button.text, storer); store(button.text, storer);
} }
template <class ParserT> template <class ParserT>
void parse(KeyboardButton &button, ParserT &parser) { void parse(KeyboardButton &button, ParserT &parser) {
if (parser.version() >= static_cast<int32>(Version::AddKeyboardButtonFlags)) {
BEGIN_PARSE_FLAGS();
END_PARSE_FLAGS();
}
parse(button.type, parser); parse(button.type, parser);
parse(button.text, parser); parse(button.text, parser);
} }
template <class StorerT> template <class StorerT>
void store(InlineKeyboardButton button, StorerT &storer) { void store(InlineKeyboardButton button, StorerT &storer) {
bool has_id = button.id != 0;
bool has_user_id = button.user_id.is_valid();
bool has_forward_text = !button.forward_text.empty();
bool has_data = !button.data.empty();
BEGIN_STORE_FLAGS();
STORE_FLAG(has_id);
STORE_FLAG(has_user_id);
STORE_FLAG(has_forward_text);
STORE_FLAG(has_data);
END_STORE_FLAGS();
store(button.type, storer); store(button.type, storer);
if (button.type == InlineKeyboardButton::Type::UrlAuth) { if (has_id) {
store(button.id, storer); store(button.id, storer);
} }
if (has_user_id) {
store(button.user_id, storer);
}
store(button.text, storer); store(button.text, storer);
if (has_forward_text) {
store(button.forward_text, storer);
}
if (has_data) {
store(button.data, storer); store(button.data, storer);
}
} }
template <class ParserT> template <class ParserT>
void parse(InlineKeyboardButton &button, ParserT &parser) { void parse(InlineKeyboardButton &button, ParserT &parser) {
if (parser.version() >= static_cast<int32>(Version::AddKeyboardButtonFlags)) {
bool has_id;
bool has_user_id;
bool has_forward_text;
bool has_data;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(has_id);
PARSE_FLAG(has_user_id);
PARSE_FLAG(has_forward_text);
PARSE_FLAG(has_data);
END_PARSE_FLAGS();
parse(button.type, parser);
if (has_id) {
parse(button.id, parser);
}
if (has_user_id) {
parse(button.user_id, parser);
}
parse(button.text, parser);
if (has_forward_text) {
parse(button.forward_text, parser);
}
if (has_data) {
parse(button.data, parser);
}
} else {
parse(button.type, parser); parse(button.type, parser);
if (button.type == InlineKeyboardButton::Type::UrlAuth) { if (button.type == InlineKeyboardButton::Type::UrlAuth) {
if (parser.version() >= static_cast<int32>(Version::Support64BitIds)) { if (parser.version() >= static_cast<int32>(Version::Support64BitIds)) {
@ -49,6 +99,7 @@ void parse(InlineKeyboardButton &button, ParserT &parser) {
} }
parse(button.text, parser); parse(button.text, parser);
parse(button.data, parser); parse(button.data, parser);
}
} }
template <class StorerT> template <class StorerT>

View File

@ -6,6 +6,8 @@
// //
#include "td/telegram/SendCodeHelper.h" #include "td/telegram/SendCodeHelper.h"
#include "td/utils/base64.h"
namespace td { namespace td {
void SendCodeHelper::on_sent_code(telegram_api::object_ptr<telegram_api::auth_sentCode> sent_code) { void SendCodeHelper::on_sent_code(telegram_api::object_ptr<telegram_api::auth_sentCode> sent_code) {
@ -26,31 +28,45 @@ td_api::object_ptr<td_api::authenticationCodeInfo> SendCodeHelper::get_authentic
max(static_cast<int32>(next_code_timestamp_.in() + 1 - 1e-9), 0)); max(static_cast<int32>(next_code_timestamp_.in() + 1 - 1e-9), 0));
} }
Result<telegram_api::auth_resendCode> SendCodeHelper::resend_code() { Result<telegram_api::auth_resendCode> SendCodeHelper::resend_code() const {
if (next_code_info_.type == AuthenticationCodeInfo::Type::None) { if (next_code_info_.type == AuthenticationCodeInfo::Type::None) {
return Status::Error(400, "Authentication code can't be resend"); return Status::Error(400, "Authentication code can't be resend");
} }
sent_code_info_ = next_code_info_;
next_code_info_ = {};
next_code_timestamp_ = {};
return telegram_api::auth_resendCode(phone_number_, phone_code_hash_); return telegram_api::auth_resendCode(phone_number_, phone_code_hash_);
} }
telegram_api::object_ptr<telegram_api::codeSettings> SendCodeHelper::get_input_code_settings(const Settings &settings) { telegram_api::object_ptr<telegram_api::codeSettings> SendCodeHelper::get_input_code_settings(const Settings &settings) {
int32 flags = 0; int32 flags = 0;
vector<BufferSlice> logout_tokens;
if (settings != nullptr) { if (settings != nullptr) {
if (settings->allow_flash_call_) { if (settings->allow_flash_call_) {
flags |= telegram_api::codeSettings::ALLOW_FLASHCALL_MASK; flags |= telegram_api::codeSettings::ALLOW_FLASHCALL_MASK;
} }
if (settings->allow_missed_call_) {
flags |= telegram_api::codeSettings::ALLOW_MISSED_CALL_MASK;
}
if (settings->is_current_phone_number_) { if (settings->is_current_phone_number_) {
flags |= telegram_api::codeSettings::CURRENT_NUMBER_MASK; flags |= telegram_api::codeSettings::CURRENT_NUMBER_MASK;
} }
if (settings->allow_sms_retriever_api_) { if (settings->allow_sms_retriever_api_) {
flags |= telegram_api::codeSettings::ALLOW_APP_HASH_MASK; flags |= telegram_api::codeSettings::ALLOW_APP_HASH_MASK;
} }
constexpr size_t MAX_LOGOUT_TOKENS = 20; // server-side limit
for (const auto &token : settings->authentication_tokens_) {
auto r_logout_token = base64url_decode(token);
if (r_logout_token.is_ok()) {
logout_tokens.push_back(BufferSlice(r_logout_token.ok()));
if (logout_tokens.size() >= MAX_LOGOUT_TOKENS) {
break;
} }
return telegram_api::make_object<telegram_api::codeSettings>(flags, false /*ignored*/, false /*ignored*/, }
false /*ignored*/); }
if (!logout_tokens.empty()) {
flags |= telegram_api::codeSettings::LOGOUT_TOKENS_MASK;
}
}
return telegram_api::make_object<telegram_api::codeSettings>(
flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, std::move(logout_tokens));
} }
telegram_api::auth_sendCode SendCodeHelper::send_code(string phone_number, const Settings &settings, int32 api_id, telegram_api::auth_sendCode SendCodeHelper::send_code(string phone_number, const Settings &settings, int32 api_id,
@ -91,6 +107,8 @@ SendCodeHelper::AuthenticationCodeInfo SendCodeHelper::get_authentication_code_i
return {AuthenticationCodeInfo::Type::Call, 0, string()}; return {AuthenticationCodeInfo::Type::Call, 0, string()};
case telegram_api::auth_codeTypeFlashCall::ID: case telegram_api::auth_codeTypeFlashCall::ID:
return {AuthenticationCodeInfo::Type::FlashCall, 0, string()}; return {AuthenticationCodeInfo::Type::FlashCall, 0, string()};
case telegram_api::auth_codeTypeMissedCall::ID:
return {AuthenticationCodeInfo::Type::MissedCall, 0, string()};
default: default:
UNREACHABLE(); UNREACHABLE();
return AuthenticationCodeInfo(); return AuthenticationCodeInfo();
@ -115,7 +133,12 @@ SendCodeHelper::AuthenticationCodeInfo SendCodeHelper::get_authentication_code_i
} }
case telegram_api::auth_sentCodeTypeFlashCall::ID: { case telegram_api::auth_sentCodeTypeFlashCall::ID: {
auto code_type = move_tl_object_as<telegram_api::auth_sentCodeTypeFlashCall>(sent_code_type_ptr); auto code_type = move_tl_object_as<telegram_api::auth_sentCodeTypeFlashCall>(sent_code_type_ptr);
return AuthenticationCodeInfo{AuthenticationCodeInfo::Type::FlashCall, 0, code_type->pattern_}; return AuthenticationCodeInfo{AuthenticationCodeInfo::Type::FlashCall, 0, std::move(code_type->pattern_)};
}
case telegram_api::auth_sentCodeTypeMissedCall::ID: {
auto code_type = move_tl_object_as<telegram_api::auth_sentCodeTypeMissedCall>(sent_code_type_ptr);
return AuthenticationCodeInfo{AuthenticationCodeInfo::Type::MissedCall, code_type->length_,
std::move(code_type->prefix_)};
} }
default: default:
UNREACHABLE(); UNREACHABLE();
@ -136,6 +159,9 @@ td_api::object_ptr<td_api::AuthenticationCodeType> SendCodeHelper::get_authentic
return td_api::make_object<td_api::authenticationCodeTypeCall>(authentication_code_info.length); return td_api::make_object<td_api::authenticationCodeTypeCall>(authentication_code_info.length);
case AuthenticationCodeInfo::Type::FlashCall: case AuthenticationCodeInfo::Type::FlashCall:
return td_api::make_object<td_api::authenticationCodeTypeFlashCall>(authentication_code_info.pattern); return td_api::make_object<td_api::authenticationCodeTypeFlashCall>(authentication_code_info.pattern);
case AuthenticationCodeInfo::Type::MissedCall:
return td_api::make_object<td_api::authenticationCodeTypeMissedCall>(authentication_code_info.pattern,
authentication_code_info.length);
default: default:
UNREACHABLE(); UNREACHABLE();
return nullptr; return nullptr;

View File

@ -19,9 +19,12 @@ namespace td {
class SendCodeHelper { class SendCodeHelper {
public: public:
void on_sent_code(telegram_api::object_ptr<telegram_api::auth_sentCode> sent_code); void on_sent_code(telegram_api::object_ptr<telegram_api::auth_sentCode> sent_code);
td_api::object_ptr<td_api::authorizationStateWaitCode> get_authorization_state_wait_code() const; td_api::object_ptr<td_api::authorizationStateWaitCode> get_authorization_state_wait_code() const;
td_api::object_ptr<td_api::authenticationCodeInfo> get_authentication_code_info_object() const; td_api::object_ptr<td_api::authenticationCodeInfo> get_authentication_code_info_object() const;
Result<telegram_api::auth_resendCode> resend_code();
Result<telegram_api::auth_resendCode> resend_code() const;
using Settings = td_api::object_ptr<td_api::phoneNumberAuthenticationSettings>; using Settings = td_api::object_ptr<td_api::phoneNumberAuthenticationSettings>;
@ -53,7 +56,7 @@ class SendCodeHelper {
static constexpr int32 SENT_CODE_FLAG_HAS_TIMEOUT = 1 << 2; static constexpr int32 SENT_CODE_FLAG_HAS_TIMEOUT = 1 << 2;
struct AuthenticationCodeInfo { struct AuthenticationCodeInfo {
enum class Type : int32 { None, Message, Sms, Call, FlashCall }; enum class Type : int32 { None, Message, Sms, Call, FlashCall, MissedCall };
Type type = Type::None; Type type = Type::None;
int32 length = 0; int32 length = 0;
string pattern; string pattern;

View File

@ -12,17 +12,17 @@
namespace td { namespace td {
string SpecialStickerSetType::animated_emoji() { SpecialStickerSetType SpecialStickerSetType::animated_emoji() {
return "animated_emoji_sticker_set"; return SpecialStickerSetType("animated_emoji_sticker_set");
} }
string SpecialStickerSetType::animated_emoji_click() { SpecialStickerSetType SpecialStickerSetType::animated_emoji_click() {
return "animated_emoji_click_sticker_set"; return SpecialStickerSetType("animated_emoji_click_sticker_set");
} }
string SpecialStickerSetType::animated_dice(const string &emoji) { SpecialStickerSetType SpecialStickerSetType::animated_dice(const string &emoji) {
CHECK(!emoji.empty()); CHECK(!emoji.empty());
return PSTRING() << "animated_dice_sticker_set#" << emoji; return SpecialStickerSetType(PSTRING() << "animated_dice_sticker_set#" << emoji);
} }
SpecialStickerSetType::SpecialStickerSetType( SpecialStickerSetType::SpecialStickerSetType(
@ -30,13 +30,13 @@ SpecialStickerSetType::SpecialStickerSetType(
CHECK(input_sticker_set != nullptr); CHECK(input_sticker_set != nullptr);
switch (input_sticker_set->get_id()) { switch (input_sticker_set->get_id()) {
case telegram_api::inputStickerSetAnimatedEmoji::ID: case telegram_api::inputStickerSetAnimatedEmoji::ID:
type_ = animated_emoji(); *this = animated_emoji();
break; break;
case telegram_api::inputStickerSetAnimatedEmojiAnimations::ID: case telegram_api::inputStickerSetAnimatedEmojiAnimations::ID:
type_ = animated_emoji_click(); *this = animated_emoji_click();
break; break;
case telegram_api::inputStickerSetDice::ID: case telegram_api::inputStickerSetDice::ID:
type_ = animated_dice(static_cast<const telegram_api::inputStickerSetDice *>(input_sticker_set.get())->emoticon_); *this = animated_dice(static_cast<const telegram_api::inputStickerSetDice *>(input_sticker_set.get())->emoticon_);
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
@ -45,17 +45,18 @@ SpecialStickerSetType::SpecialStickerSetType(
} }
string SpecialStickerSetType::get_dice_emoji() const { string SpecialStickerSetType::get_dice_emoji() const {
if (begins_with(type_, "animated_dice_sticker_set#")) { auto prefix = Slice("animated_dice_sticker_set#");
return type_.substr(Slice("animated_dice_sticker_set#").size()); if (begins_with(type_, prefix)) {
return type_.substr(prefix.size());
} }
return string(); return string();
} }
telegram_api::object_ptr<telegram_api::InputStickerSet> SpecialStickerSetType::get_input_sticker_set() const { telegram_api::object_ptr<telegram_api::InputStickerSet> SpecialStickerSetType::get_input_sticker_set() const {
if (type_ == animated_emoji()) { if (*this == animated_emoji()) {
return telegram_api::make_object<telegram_api::inputStickerSetAnimatedEmoji>(); return telegram_api::make_object<telegram_api::inputStickerSetAnimatedEmoji>();
} }
if (type_ == animated_emoji_click()) { if (*this == animated_emoji_click()) {
return telegram_api::make_object<telegram_api::inputStickerSetAnimatedEmojiAnimations>(); return telegram_api::make_object<telegram_api::inputStickerSetAnimatedEmojiAnimations>();
} }
auto emoji = get_dice_emoji(); auto emoji = get_dice_emoji();

View File

@ -10,19 +10,31 @@
#include "td/utils/common.h" #include "td/utils/common.h"
#include <functional>
namespace td { namespace td {
struct SpecialStickerSetType { class SpecialStickerSetType {
explicit SpecialStickerSetType(string type) : type_(type) {
}
friend struct SpecialStickerSetTypeHash;
public:
string type_; string type_;
static string animated_emoji(); static SpecialStickerSetType animated_emoji();
static string animated_emoji_click(); static SpecialStickerSetType animated_emoji_click();
static string animated_dice(const string &emoji); static SpecialStickerSetType animated_dice(const string &emoji);
string get_dice_emoji() const; string get_dice_emoji() const;
bool is_empty() const {
return type_.empty();
}
SpecialStickerSetType() = default; SpecialStickerSetType() = default;
explicit SpecialStickerSetType(const telegram_api::object_ptr<telegram_api::InputStickerSet> &input_sticker_set); explicit SpecialStickerSetType(const telegram_api::object_ptr<telegram_api::InputStickerSet> &input_sticker_set);
@ -30,4 +42,18 @@ struct SpecialStickerSetType {
telegram_api::object_ptr<telegram_api::InputStickerSet> get_input_sticker_set() const; telegram_api::object_ptr<telegram_api::InputStickerSet> get_input_sticker_set() const;
}; };
inline bool operator==(const SpecialStickerSetType &lhs, const SpecialStickerSetType &rhs) {
return lhs.type_ == rhs.type_;
}
inline bool operator!=(const SpecialStickerSetType &lhs, const SpecialStickerSetType &rhs) {
return !(lhs == rhs);
}
struct SpecialStickerSetTypeHash {
std::size_t operator()(SpecialStickerSetType type) const {
return std::hash<string>()(type.type_);
}
};
} // namespace td } // namespace td

View File

@ -290,6 +290,9 @@ void SponsoredMessageManager::view_sponsored_message(DialogId dialog_id, int32 s
if (!td_->messages_manager_->have_dialog_force(dialog_id, "view_sponsored_message")) { if (!td_->messages_manager_->have_dialog_force(dialog_id, "view_sponsored_message")) {
return promise.set_error(Status::Error(400, "Chat not found")); return promise.set_error(Status::Error(400, "Chat not found"));
} }
if (!td_->messages_manager_->is_dialog_opened(dialog_id)) {
return promise.set_value(Unit());
}
auto it = dialog_sponsored_messages_.find(dialog_id); auto it = dialog_sponsored_messages_.find(dialog_id);
if (it == dialog_sponsored_messages_.end()) { if (it == dialog_sponsored_messages_.end()) {

View File

@ -660,13 +660,14 @@ class GetStickerSetQuery final : public Td::ResultHandler {
explicit GetStickerSetQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) { explicit GetStickerSetQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
} }
void send(StickerSetId sticker_set_id, tl_object_ptr<telegram_api::InputStickerSet> &&input_sticker_set) { void send(StickerSetId sticker_set_id, tl_object_ptr<telegram_api::InputStickerSet> &&input_sticker_set, int32 hash) {
sticker_set_id_ = sticker_set_id; sticker_set_id_ = sticker_set_id;
if (input_sticker_set->get_id() == telegram_api::inputStickerSetShortName::ID) { if (input_sticker_set->get_id() == telegram_api::inputStickerSetShortName::ID) {
sticker_set_name_ = sticker_set_name_ =
static_cast<const telegram_api::inputStickerSetShortName *>(input_sticker_set.get())->short_name_; static_cast<const telegram_api::inputStickerSetShortName *>(input_sticker_set.get())->short_name_;
} }
send_query(G()->net_query_creator().create(telegram_api::messages_getStickerSet(std::move(input_sticker_set)))); send_query(
G()->net_query_creator().create(telegram_api::messages_getStickerSet(std::move(input_sticker_set), hash)));
} }
void on_result(BufferSlice packet) final { void on_result(BufferSlice packet) final {
@ -675,8 +676,9 @@ class GetStickerSetQuery final : public Td::ResultHandler {
return on_error(result_ptr.move_as_error()); return on_error(result_ptr.move_as_error());
} }
auto set = result_ptr.move_as_ok(); auto set_ptr = result_ptr.move_as_ok();
if (set_ptr->get_id() == telegram_api::messages_stickerSet::ID) {
auto set = static_cast<telegram_api::messages_stickerSet *>(set_ptr.get());
constexpr int64 GREAT_MINDS_COLOR_SET_ID = 151353307481243663; constexpr int64 GREAT_MINDS_COLOR_SET_ID = 151353307481243663;
if (set->set_->id_ == GREAT_MINDS_COLOR_SET_ID) { if (set->set_->id_ == GREAT_MINDS_COLOR_SET_ID) {
string great_minds_name = "TelegramGreatMinds"; string great_minds_name = "TelegramGreatMinds";
@ -686,8 +688,10 @@ class GetStickerSetQuery final : public Td::ResultHandler {
set->set_->short_name_ = std::move(great_minds_name); set->set_->short_name_ = std::move(great_minds_name);
} }
} }
}
td_->stickers_manager_->on_get_messages_sticker_set(sticker_set_id_, std::move(set), true, "GetStickerSetQuery"); td_->stickers_manager_->on_get_messages_sticker_set(sticker_set_id_, std::move(set_ptr), true,
"GetStickerSetQuery");
promise_.set_value(Unit()); promise_.set_value(Unit());
} }
@ -700,12 +704,15 @@ class GetStickerSetQuery final : public Td::ResultHandler {
}; };
class ReloadSpecialStickerSetQuery final : public Td::ResultHandler { class ReloadSpecialStickerSetQuery final : public Td::ResultHandler {
StickerSetId sticker_set_id_;
SpecialStickerSetType type_; SpecialStickerSetType type_;
public: public:
void send(SpecialStickerSetType type) { void send(StickerSetId sticker_set_id, SpecialStickerSetType type, int32 hash) {
sticker_set_id_ = sticker_set_id;
type_ = std::move(type); type_ = std::move(type);
send_query(G()->net_query_creator().create(telegram_api::messages_getStickerSet(type_.get_input_sticker_set()))); send_query(
G()->net_query_creator().create(telegram_api::messages_getStickerSet(type_.get_input_sticker_set(), hash)));
} }
void on_result(BufferSlice packet) final { void on_result(BufferSlice packet) final {
@ -714,10 +721,17 @@ class ReloadSpecialStickerSetQuery final : public Td::ResultHandler {
return on_error(result_ptr.move_as_error()); return on_error(result_ptr.move_as_error());
} }
auto sticker_set_id = td_->stickers_manager_->on_get_messages_sticker_set(StickerSetId(), result_ptr.move_as_ok(), auto set_ptr = result_ptr.move_as_ok();
true, "ReloadSpecialStickerSetQuery"); if (set_ptr->get_id() == telegram_api::messages_stickerSet::ID) {
if (sticker_set_id.is_valid()) { // sticker_set_id_ needs to be replaced always
td_->stickers_manager_->on_get_special_sticker_set(type_, sticker_set_id); sticker_set_id_ = td_->stickers_manager_->on_get_messages_sticker_set(StickerSetId(), std::move(set_ptr), true,
"ReloadSpecialStickerSetQuery");
} else if (sticker_set_id_.is_valid()) {
td_->stickers_manager_->on_get_messages_sticker_set(sticker_set_id_, std::move(set_ptr), false,
"ReloadSpecialStickerSetQuery");
}
if (sticker_set_id_.is_valid()) {
td_->stickers_manager_->on_get_special_sticker_set(type_, sticker_set_id_);
} else { } else {
on_error(Status::Error(500, "Failed to add special sticker set")); on_error(Status::Error(500, "Failed to add special sticker set"));
} }
@ -1256,7 +1270,6 @@ void StickersManager::init() {
init_special_sticker_set(sticker_set, 1258816259751983, 5100237018658464041, "AnimatedEmojies"); init_special_sticker_set(sticker_set, 1258816259751983, 5100237018658464041, "AnimatedEmojies");
} }
load_special_sticker_set_info_from_binlog(sticker_set); load_special_sticker_set_info_from_binlog(sticker_set);
G()->shared_config().set_option_string(PSLICE() << sticker_set.type_.type_ << "_name", sticker_set.short_name_);
} }
if (!G()->is_test_dc()) { if (!G()->is_test_dc()) {
// add animated emoji click sticker set // add animated emoji click sticker set
@ -1297,14 +1310,15 @@ void StickersManager::init() {
G()->td_db()->get_binlog_pmc()->erase("animated_dice_sticker_set"); // legacy G()->td_db()->get_binlog_pmc()->erase("animated_dice_sticker_set"); // legacy
G()->shared_config().set_option_empty("animated_dice_sticker_set_name"); // legacy G()->shared_config().set_option_empty("animated_dice_sticker_set_name"); // legacy
G()->shared_config().set_option_empty("animated_emoji_sticker_set_name"); // legacy
} }
StickersManager::SpecialStickerSet &StickersManager::add_special_sticker_set(const string &type) { StickersManager::SpecialStickerSet &StickersManager::add_special_sticker_set(const SpecialStickerSetType &type) {
auto &result = special_sticker_sets_[type]; auto &result = special_sticker_sets_[type];
if (result.type_.type_.empty()) { if (result.type_.is_empty()) {
result.type_.type_ = type; result.type_ = type;
} else { } else {
CHECK(result.type_.type_ == type); CHECK(result.type_ == type);
} }
return result; return result;
} }
@ -1348,12 +1362,12 @@ void StickersManager::load_special_sticker_set_info_from_binlog(SpecialStickerSe
short_name_to_sticker_set_id_.emplace(sticker_set.short_name_, sticker_set.id_); short_name_to_sticker_set_id_.emplace(sticker_set.short_name_, sticker_set.id_);
} }
void StickersManager::load_special_sticker_set_by_type(const SpecialStickerSetType &type) { void StickersManager::load_special_sticker_set_by_type(SpecialStickerSetType type) {
if (G()->close_flag()) { if (G()->close_flag()) {
return; return;
} }
auto &sticker_set = add_special_sticker_set(type.type_); auto &sticker_set = add_special_sticker_set(type);
CHECK(sticker_set.is_being_loaded_); CHECK(sticker_set.is_being_loaded_);
sticker_set.is_being_loaded_ = false; sticker_set.is_being_loaded_ = false;
load_special_sticker_set(sticker_set); load_special_sticker_set(sticker_set);
@ -1373,12 +1387,44 @@ void StickersManager::load_special_sticker_set(SpecialStickerSet &sticker_set) {
}); });
load_sticker_sets({sticker_set.id_}, std::move(promise)); load_sticker_sets({sticker_set.id_}, std::move(promise));
} else { } else {
reload_special_sticker_set(sticker_set); reload_special_sticker_set(sticker_set, 0);
} }
} }
void StickersManager::reload_special_sticker_set(SpecialStickerSet &sticker_set) { void StickersManager::reload_special_sticker_set_by_type(SpecialStickerSetType type, bool is_recursive) {
td_->create_handler<ReloadSpecialStickerSetQuery>()->send(sticker_set.type_); if (G()->close_flag()) {
return;
}
auto &sticker_set = add_special_sticker_set(type);
if (sticker_set.is_being_reloaded_) {
return;
}
if (!sticker_set.id_.is_valid()) {
return reload_special_sticker_set(sticker_set, 0);
}
const auto *s = get_sticker_set(sticker_set.id_);
if (s != nullptr && s->is_inited && s->was_loaded) {
return reload_special_sticker_set(sticker_set, s->is_loaded ? s->hash : 0);
}
if (!is_recursive) {
auto promise = PromiseCreator::lambda([actor_id = actor_id(this), type = std::move(type)](Unit result) mutable {
send_closure(actor_id, &StickersManager::reload_special_sticker_set_by_type, std::move(type), true);
});
return load_sticker_sets({sticker_set.id_}, std::move(promise));
}
reload_special_sticker_set(sticker_set, 0);
}
void StickersManager::reload_special_sticker_set(SpecialStickerSet &sticker_set, int32 hash) {
if (sticker_set.is_being_reloaded_) {
return;
}
sticker_set.is_being_reloaded_ = true;
td_->create_handler<ReloadSpecialStickerSetQuery>()->send(sticker_set.id_, sticker_set.type_, hash);
} }
void StickersManager::on_load_special_sticker_set(const SpecialStickerSetType &type, Status result) { void StickersManager::on_load_special_sticker_set(const SpecialStickerSetType &type, Status result) {
@ -1386,7 +1432,8 @@ void StickersManager::on_load_special_sticker_set(const SpecialStickerSetType &t
return; return;
} }
auto &special_sticker_set = add_special_sticker_set(type.type_); auto &special_sticker_set = add_special_sticker_set(type);
special_sticker_set.is_being_reloaded_ = false;
if (!special_sticker_set.is_being_loaded_) { if (!special_sticker_set.is_being_loaded_) {
return; return;
} }
@ -1394,8 +1441,9 @@ void StickersManager::on_load_special_sticker_set(const SpecialStickerSetType &t
if (result.is_error()) { if (result.is_error()) {
// failed to load the special sticker set; repeat after some time // failed to load the special sticker set; repeat after some time
create_actor<SleepActor>("RetryLoadSpecialStickerSetActor", Random::fast(300, 600), create_actor<SleepActor>("RetryLoadSpecialStickerSetActor", Random::fast(300, 600),
PromiseCreator::lambda([actor_id = actor_id(this), type](Result<Unit> result) { PromiseCreator::lambda([actor_id = actor_id(this), type](Result<Unit> result) mutable {
send_closure(actor_id, &StickersManager::load_special_sticker_set_by_type, type); send_closure(actor_id, &StickersManager::load_special_sticker_set_by_type,
std::move(type));
})) }))
.release(); .release();
return; return;
@ -1403,7 +1451,7 @@ void StickersManager::on_load_special_sticker_set(const SpecialStickerSetType &t
special_sticker_set.is_being_loaded_ = false; special_sticker_set.is_being_loaded_ = false;
if (type.type_ == SpecialStickerSetType::animated_emoji()) { if (type == SpecialStickerSetType::animated_emoji()) {
auto promises = std::move(pending_get_animated_emoji_queries_); auto promises = std::move(pending_get_animated_emoji_queries_);
reset_to_empty(pending_get_animated_emoji_queries_); reset_to_empty(pending_get_animated_emoji_queries_);
for (auto &promise : promises) { for (auto &promise : promises) {
@ -1417,7 +1465,7 @@ void StickersManager::on_load_special_sticker_set(const SpecialStickerSetType &t
CHECK(sticker_set != nullptr); CHECK(sticker_set != nullptr);
CHECK(sticker_set->was_loaded); CHECK(sticker_set->was_loaded);
if (type.type_ == SpecialStickerSetType::animated_emoji_click()) { if (type == SpecialStickerSetType::animated_emoji_click()) {
auto pending_get_requests = std::move(pending_get_animated_emoji_click_stickers_); auto pending_get_requests = std::move(pending_get_animated_emoji_click_stickers_);
reset_to_empty(pending_get_animated_emoji_click_stickers_); reset_to_empty(pending_get_animated_emoji_click_stickers_);
for (auto &pending_request : pending_get_requests) { for (auto &pending_request : pending_get_requests) {
@ -1982,33 +2030,6 @@ FileId StickersManager::get_animated_emoji_sound_file_id(const string &emoji) co
return it->second; return it->second;
} }
vector<td_api::object_ptr<td_api::colorReplacement>> StickersManager::get_color_replacements_object(
int fitzpatrick_modifier) {
vector<td_api::object_ptr<td_api::colorReplacement>> result;
switch (fitzpatrick_modifier) {
case 0:
break;
case 2:
case 3:
case 4:
case 5:
case 6: {
static int32 old_colors[] = {0xf77e41, 0xffb139, 0xffd140, 0xffdf79};
static int32 new_colors[] = {0xcb7b55, 0xf6b689, 0xffcda7, 0xffdfc5, 0xa45a38, 0xdf986b, 0xedb183,
0xf4c3a0, 0x703a17, 0xab673d, 0xc37f4e, 0xd89667, 0x4a2409, 0x7d3e0e,
0x965529, 0xa96337, 0x200f0a, 0x412924, 0x593d37, 0x63453f};
for (size_t i = 0; i < 4; i++) {
result.push_back(td_api::make_object<td_api::colorReplacement>(old_colors[i],
new_colors[(fitzpatrick_modifier - 2) * 4 + i]));
}
break;
}
default:
UNREACHABLE();
}
return result;
}
td_api::object_ptr<td_api::animatedEmoji> StickersManager::get_animated_emoji_object(const string &emoji) { td_api::object_ptr<td_api::animatedEmoji> StickersManager::get_animated_emoji_object(const string &emoji) {
auto it = emoji_messages_.find(emoji); auto it = emoji_messages_.find(emoji);
if (it == emoji_messages_.end()) { if (it == emoji_messages_.end()) {
@ -2024,7 +2045,7 @@ td_api::object_ptr<td_api::animatedEmoji> StickersManager::get_animated_emoji_ob
return nullptr; return nullptr;
} }
return td_api::make_object<td_api::animatedEmoji>( return td_api::make_object<td_api::animatedEmoji>(
get_sticker_object(animated_sticker.first, true), get_color_replacements_object(animated_sticker.second), get_sticker_object(animated_sticker.first, true), animated_sticker.second,
sound_file_id.is_valid() ? td_->file_manager_->get_file_object(sound_file_id) : nullptr); sound_file_id.is_valid() ? td_->file_manager_->get_file_object(sound_file_id) : nullptr);
} }
@ -2228,7 +2249,7 @@ StickerSetId StickersManager::get_sticker_set_id(const tl_object_ptr<telegram_ap
case telegram_api::inputStickerSetAnimatedEmoji::ID: case telegram_api::inputStickerSetAnimatedEmoji::ID:
case telegram_api::inputStickerSetAnimatedEmojiAnimations::ID: case telegram_api::inputStickerSetAnimatedEmojiAnimations::ID:
LOG(ERROR) << "Receive special sticker set " << to_string(set_ptr); LOG(ERROR) << "Receive special sticker set " << to_string(set_ptr);
return add_special_sticker_set(SpecialStickerSetType(set_ptr).type_).id_; return add_special_sticker_set(SpecialStickerSetType(set_ptr)).id_;
case telegram_api::inputStickerSetDice::ID: case telegram_api::inputStickerSetDice::ID:
LOG(ERROR) << "Receive special sticker set " << to_string(set_ptr); LOG(ERROR) << "Receive special sticker set " << to_string(set_ptr);
return StickerSetId(); return StickerSetId();
@ -2257,7 +2278,7 @@ StickerSetId StickersManager::add_sticker_set(tl_object_ptr<telegram_api::InputS
case telegram_api::inputStickerSetAnimatedEmoji::ID: case telegram_api::inputStickerSetAnimatedEmoji::ID:
case telegram_api::inputStickerSetAnimatedEmojiAnimations::ID: case telegram_api::inputStickerSetAnimatedEmojiAnimations::ID:
LOG(ERROR) << "Receive special sticker set " << to_string(set_ptr); LOG(ERROR) << "Receive special sticker set " << to_string(set_ptr);
return add_special_sticker_set(SpecialStickerSetType(set_ptr).type_).id_; return add_special_sticker_set(SpecialStickerSetType(set_ptr)).id_;
case telegram_api::inputStickerSetDice::ID: case telegram_api::inputStickerSetDice::ID:
LOG(ERROR) << "Receive special sticker set " << to_string(set_ptr); LOG(ERROR) << "Receive special sticker set " << to_string(set_ptr);
return StickerSetId(); return StickerSetId();
@ -2444,7 +2465,7 @@ StickerSetId StickersManager::on_get_input_sticker_set(FileId sticker_file_id,
} }
case telegram_api::inputStickerSetAnimatedEmoji::ID: case telegram_api::inputStickerSetAnimatedEmoji::ID:
case telegram_api::inputStickerSetAnimatedEmojiAnimations::ID: case telegram_api::inputStickerSetAnimatedEmojiAnimations::ID:
return add_special_sticker_set(SpecialStickerSetType(set_ptr).type_).id_; return add_special_sticker_set(SpecialStickerSetType(set_ptr)).id_;
case telegram_api::inputStickerSetDice::ID: case telegram_api::inputStickerSetDice::ID:
return StickerSetId(); return StickerSetId();
default: default:
@ -2861,9 +2882,24 @@ StickerSetId StickersManager::on_get_sticker_set_covered(tl_object_ptr<telegram_
} }
StickerSetId StickersManager::on_get_messages_sticker_set(StickerSetId sticker_set_id, StickerSetId StickersManager::on_get_messages_sticker_set(StickerSetId sticker_set_id,
tl_object_ptr<telegram_api::messages_stickerSet> &&set, tl_object_ptr<telegram_api::messages_StickerSet> &&set_ptr,
bool is_changed, const char *source) { bool is_changed, const char *source) {
LOG(INFO) << "Receive sticker set " << to_string(set); LOG(INFO) << "Receive sticker set " << to_string(set_ptr);
if (set_ptr->get_id() == telegram_api::messages_stickerSetNotModified::ID) {
if (!sticker_set_id.is_valid()) {
LOG(ERROR) << "Receive unexpected stickerSetNotModified from " << source;
} else {
auto s = get_sticker_set(sticker_set_id);
CHECK(s != nullptr);
CHECK(s->is_inited);
CHECK(s->was_loaded);
s->expires_at = G()->unix_time() +
(td_->auth_manager_->is_bot() ? Random::fast(10 * 60, 15 * 60) : Random::fast(30 * 60, 50 * 60));
}
return sticker_set_id;
}
auto set = move_tl_object_as<telegram_api::messages_stickerSet>(set_ptr);
auto set_id = on_get_sticker_set(std::move(set->set_), is_changed, source); auto set_id = on_get_sticker_set(std::move(set->set_), is_changed, source);
if (!set_id.is_valid()) { if (!set_id.is_valid()) {
@ -3008,7 +3044,7 @@ void StickersManager::on_get_special_sticker_set(const SpecialStickerSetType &ty
LOG(INFO) << "Receive special sticker set " << type.type_ << ": " << sticker_set_id << ' ' << s->access_hash << ' ' LOG(INFO) << "Receive special sticker set " << type.type_ << ": " << sticker_set_id << ' ' << s->access_hash << ' '
<< s->short_name; << s->short_name;
auto &sticker_set = add_special_sticker_set(type.type_); auto &sticker_set = add_special_sticker_set(type);
if (sticker_set_id == sticker_set.id_ && s->access_hash == sticker_set.access_hash_ && if (sticker_set_id == sticker_set.id_ && s->access_hash == sticker_set.access_hash_ &&
s->short_name == sticker_set.short_name_ && !s->short_name.empty()) { s->short_name == sticker_set.short_name_ && !s->short_name.empty()) {
on_load_special_sticker_set(type, Status::OK()); on_load_special_sticker_set(type, Status::OK());
@ -3022,8 +3058,7 @@ void StickersManager::on_get_special_sticker_set(const SpecialStickerSetType &ty
G()->td_db()->get_binlog_pmc()->set(type.type_, PSTRING() << sticker_set.id_.get() << ' ' << sticker_set.access_hash_ G()->td_db()->get_binlog_pmc()->set(type.type_, PSTRING() << sticker_set.id_.get() << ' ' << sticker_set.access_hash_
<< ' ' << sticker_set.short_name_); << ' ' << sticker_set.short_name_);
if (type.type_ == SpecialStickerSetType::animated_emoji()) { if (type == SpecialStickerSetType::animated_emoji()) {
G()->shared_config().set_option_string(PSLICE() << type.type_ << "_name", sticker_set.short_name_);
try_update_animated_emoji_messages(); try_update_animated_emoji_messages();
} else if (!type.get_dice_emoji().empty()) { } else if (!type.get_dice_emoji().empty()) {
sticker_set.is_being_loaded_ = true; sticker_set.is_being_loaded_ = true;
@ -3444,10 +3479,10 @@ bool StickersManager::update_sticker_set_cache(const StickerSet *sticker_set, Pr
} else { } else {
if (G()->unix_time() >= sticker_set->expires_at) { if (G()->unix_time() >= sticker_set->expires_at) {
if (td_->auth_manager_->is_bot()) { if (td_->auth_manager_->is_bot()) {
do_reload_sticker_set(set_id, get_input_sticker_set(sticker_set), std::move(promise)); do_reload_sticker_set(set_id, get_input_sticker_set(sticker_set), sticker_set->hash, std::move(promise));
return true; return true;
} else { } else {
do_reload_sticker_set(set_id, get_input_sticker_set(sticker_set), Auto()); do_reload_sticker_set(set_id, get_input_sticker_set(sticker_set), sticker_set->hash, Auto());
} }
} }
} }
@ -3459,7 +3494,7 @@ StickerSetId StickersManager::get_sticker_set(StickerSetId set_id, Promise<Unit>
const StickerSet *sticker_set = get_sticker_set(set_id); const StickerSet *sticker_set = get_sticker_set(set_id);
if (sticker_set == nullptr) { if (sticker_set == nullptr) {
if (set_id.get() == GREAT_MINDS_SET_ID) { if (set_id.get() == GREAT_MINDS_SET_ID) {
do_reload_sticker_set(set_id, make_tl_object<telegram_api::inputStickerSetID>(set_id.get(), 0), do_reload_sticker_set(set_id, make_tl_object<telegram_api::inputStickerSetID>(set_id.get(), 0), 0,
std::move(promise)); std::move(promise));
return StickerSetId(); return StickerSetId();
} }
@ -3483,7 +3518,7 @@ StickerSetId StickersManager::search_sticker_set(const string &short_name_to_sea
if (sticker_set == nullptr) { if (sticker_set == nullptr) {
auto set_to_load = make_tl_object<telegram_api::inputStickerSetShortName>(short_name); auto set_to_load = make_tl_object<telegram_api::inputStickerSetShortName>(short_name);
do_reload_sticker_set(StickerSetId(), std::move(set_to_load), std::move(promise)); do_reload_sticker_set(StickerSetId(), std::move(set_to_load), 0, std::move(promise));
return StickerSetId(); return StickerSetId();
} }
@ -3871,7 +3906,7 @@ void StickersManager::load_sticker_sets(vector<StickerSetId> &&sticker_set_ids,
})); }));
} else { } else {
LOG(INFO) << "Trying to load " << sticker_set_id << " with stickers from server"; LOG(INFO) << "Trying to load " << sticker_set_id << " with stickers from server";
do_reload_sticker_set(sticker_set_id, get_input_sticker_set(sticker_set), Auto()); do_reload_sticker_set(sticker_set_id, get_input_sticker_set(sticker_set), 0, Auto());
} }
} }
} }
@ -3908,7 +3943,7 @@ void StickersManager::load_sticker_sets_without_stickers(vector<StickerSetId> &&
})); }));
} else { } else {
LOG(INFO) << "Trying to load " << sticker_set_id << " from server"; LOG(INFO) << "Trying to load " << sticker_set_id << " from server";
do_reload_sticker_set(sticker_set_id, get_input_sticker_set(sticker_set), Auto()); do_reload_sticker_set(sticker_set_id, get_input_sticker_set(sticker_set), 0, Auto());
} }
} }
} }
@ -3939,7 +3974,7 @@ void StickersManager::on_load_sticker_set_from_database(StickerSetId sticker_set
if (value.empty()) { if (value.empty()) {
LOG(INFO) << "Failed to find in the database " << sticker_set_id; LOG(INFO) << "Failed to find in the database " << sticker_set_id;
return do_reload_sticker_set(sticker_set_id, get_input_sticker_set(sticker_set), Auto()); return do_reload_sticker_set(sticker_set_id, get_input_sticker_set(sticker_set), 0, Auto());
} }
LOG(INFO) << "Successfully loaded " << sticker_set_id << " with" << (with_stickers ? "" : "out") LOG(INFO) << "Successfully loaded " << sticker_set_id << " with" << (with_stickers ? "" : "out")
@ -3965,7 +4000,7 @@ void StickersManager::on_load_sticker_set_from_database(StickerSetId sticker_set
} }
} }
if (!sticker_set->is_thumbnail_reloaded || !sticker_set->are_legacy_sticker_thumbnails_reloaded) { if (!sticker_set->is_thumbnail_reloaded || !sticker_set->are_legacy_sticker_thumbnails_reloaded) {
do_reload_sticker_set(sticker_set_id, get_input_sticker_set(sticker_set), Auto()); do_reload_sticker_set(sticker_set_id, get_input_sticker_set(sticker_set), 0, Auto());
} }
if (with_stickers && old_sticker_count < 5 && old_sticker_count < sticker_set->sticker_ids.size()) { if (with_stickers && old_sticker_count < 5 && old_sticker_count < sticker_set->sticker_ids.size()) {
@ -3978,15 +4013,15 @@ void StickersManager::on_load_sticker_set_from_database(StickerSetId sticker_set
void StickersManager::reload_sticker_set(StickerSetId sticker_set_id, int64 access_hash, Promise<Unit> &&promise) { void StickersManager::reload_sticker_set(StickerSetId sticker_set_id, int64 access_hash, Promise<Unit> &&promise) {
do_reload_sticker_set(sticker_set_id, do_reload_sticker_set(sticker_set_id,
make_tl_object<telegram_api::inputStickerSetID>(sticker_set_id.get(), access_hash), make_tl_object<telegram_api::inputStickerSetID>(sticker_set_id.get(), access_hash), 0,
std::move(promise)); std::move(promise));
} }
void StickersManager::do_reload_sticker_set(StickerSetId sticker_set_id, void StickersManager::do_reload_sticker_set(StickerSetId sticker_set_id,
tl_object_ptr<telegram_api::InputStickerSet> &&input_sticker_set, tl_object_ptr<telegram_api::InputStickerSet> &&input_sticker_set,
Promise<Unit> &&promise) const { int32 hash, Promise<Unit> &&promise) const {
TRY_STATUS_PROMISE(promise, G()->close_status()); TRY_STATUS_PROMISE(promise, G()->close_status());
td_->create_handler<GetStickerSetQuery>(std::move(promise))->send(sticker_set_id, std::move(input_sticker_set)); td_->create_handler<GetStickerSetQuery>(std::move(promise))->send(sticker_set_id, std::move(input_sticker_set), hash);
} }
void StickersManager::on_install_sticker_set(StickerSetId set_id, bool is_archived, void StickersManager::on_install_sticker_set(StickerSetId set_id, bool is_archived,
@ -4152,7 +4187,8 @@ void StickersManager::on_update_disable_animated_emojis() {
} }
disable_animated_emojis_ = disable_animated_emojis; disable_animated_emojis_ = disable_animated_emojis;
if (!disable_animated_emojis_) { if (!disable_animated_emojis_) {
load_special_sticker_set(add_special_sticker_set(SpecialStickerSetType::animated_emoji())); reload_special_sticker_set_by_type(SpecialStickerSetType::animated_emoji());
reload_special_sticker_set_by_type(SpecialStickerSetType::animated_emoji_click());
} }
try_update_animated_emoji_messages(); try_update_animated_emoji_messages();
} }
@ -4210,10 +4246,11 @@ void StickersManager::register_dice(const string &emoji, int32 value, FullMessag
auto &special_sticker_set = add_special_sticker_set(SpecialStickerSetType::animated_dice(emoji)); auto &special_sticker_set = add_special_sticker_set(SpecialStickerSetType::animated_dice(emoji));
bool need_load = false; bool need_load = false;
StickerSet *sticker_set = nullptr;
if (!special_sticker_set.id_.is_valid()) { if (!special_sticker_set.id_.is_valid()) {
need_load = true; need_load = true;
} else { } else {
auto sticker_set = get_sticker_set(special_sticker_set.id_); sticker_set = get_sticker_set(special_sticker_set.id_);
CHECK(sticker_set != nullptr); CHECK(sticker_set != nullptr);
need_load = !sticker_set->was_loaded; need_load = !sticker_set->was_loaded;
} }
@ -4223,7 +4260,7 @@ void StickersManager::register_dice(const string &emoji, int32 value, FullMessag
load_special_sticker_set(special_sticker_set); load_special_sticker_set(special_sticker_set);
} else { } else {
// TODO reload once in a while // TODO reload once in a while
// reload_special_sticker_set(special_sticker_set); // reload_special_sticker_set(special_sticker_set, sticker_set->is_loaded ? sticker_set->hash : 0);
} }
} }
@ -5874,7 +5911,7 @@ void StickersManager::set_sticker_set_thumbnail(UserId user_id, string &short_na
} }
do_reload_sticker_set( do_reload_sticker_set(
StickerSetId(), make_tl_object<telegram_api::inputStickerSetShortName>(short_name), StickerSetId(), make_tl_object<telegram_api::inputStickerSetShortName>(short_name), 0,
PromiseCreator::lambda([actor_id = actor_id(this), user_id, short_name, thumbnail = std::move(thumbnail), PromiseCreator::lambda([actor_id = actor_id(this), user_id, short_name, thumbnail = std::move(thumbnail),
promise = std::move(promise)](Result<Unit> result) mutable { promise = std::move(promise)](Result<Unit> result) mutable {
if (result.is_error()) { if (result.is_error()) {
@ -7388,8 +7425,10 @@ void StickersManager::after_get_difference() {
get_recent_stickers(true, Auto()); get_recent_stickers(true, Auto());
get_favorite_stickers(Auto()); get_favorite_stickers(Auto());
reload_special_sticker_set(add_special_sticker_set(SpecialStickerSetType::animated_emoji())); if (!disable_animated_emojis_) {
reload_special_sticker_set(add_special_sticker_set(SpecialStickerSetType::animated_emoji_click())); reload_special_sticker_set_by_type(SpecialStickerSetType::animated_emoji());
reload_special_sticker_set_by_type(SpecialStickerSetType::animated_emoji_click());
}
} }
} }

View File

@ -135,7 +135,7 @@ class StickersManager final : public Actor {
void on_get_installed_sticker_sets_failed(bool is_masks, Status error); void on_get_installed_sticker_sets_failed(bool is_masks, Status error);
StickerSetId on_get_messages_sticker_set(StickerSetId sticker_set_id, StickerSetId on_get_messages_sticker_set(StickerSetId sticker_set_id,
tl_object_ptr<telegram_api::messages_stickerSet> &&set, bool is_changed, tl_object_ptr<telegram_api::messages_StickerSet> &&set_ptr, bool is_changed,
const char *source); const char *source);
StickerSetId on_get_sticker_set(tl_object_ptr<telegram_api::stickerSet> &&set, bool is_changed, const char *source); StickerSetId on_get_sticker_set(tl_object_ptr<telegram_api::stickerSet> &&set, bool is_changed, const char *source);
@ -438,6 +438,7 @@ class StickersManager final : public Actor {
string short_name_; string short_name_;
SpecialStickerSetType type_; SpecialStickerSetType type_;
bool is_being_loaded_ = false; bool is_being_loaded_ = false;
bool is_being_reloaded_ = false;
}; };
class StickerListLogEvent; class StickerListLogEvent;
@ -497,7 +498,7 @@ class StickersManager final : public Actor {
void update_load_request(uint32 load_request_id, const Status &status); void update_load_request(uint32 load_request_id, const Status &status);
void do_reload_sticker_set(StickerSetId sticker_set_id, void do_reload_sticker_set(StickerSetId sticker_set_id,
tl_object_ptr<telegram_api::InputStickerSet> &&input_sticker_set, tl_object_ptr<telegram_api::InputStickerSet> &&input_sticker_set, int32 hash,
Promise<Unit> &&promise) const; Promise<Unit> &&promise) const;
static void read_featured_sticker_sets(void *td_void); static void read_featured_sticker_sets(void *td_void);
@ -615,8 +616,6 @@ class StickersManager final : public Actor {
bool update_sticker_set_cache(const StickerSet *sticker_set, Promise<Unit> &promise); bool update_sticker_set_cache(const StickerSet *sticker_set, Promise<Unit> &promise);
static vector<td_api::object_ptr<td_api::colorReplacement>> get_color_replacements_object(int fitzpatrick_modifier);
const StickerSet *get_animated_emoji_sticker_set(); const StickerSet *get_animated_emoji_sticker_set();
static std::pair<FileId, int> get_animated_emoji_sticker(const StickerSet *sticker_set, const string &emoji); static std::pair<FileId, int> get_animated_emoji_sticker(const StickerSet *sticker_set, const string &emoji);
@ -658,18 +657,20 @@ class StickersManager final : public Actor {
void tear_down() final; void tear_down() final;
SpecialStickerSet &add_special_sticker_set(const string &type); SpecialStickerSet &add_special_sticker_set(const SpecialStickerSetType &type);
static void init_special_sticker_set(SpecialStickerSet &sticker_set, int64 sticker_set_id, int64 access_hash, static void init_special_sticker_set(SpecialStickerSet &sticker_set, int64 sticker_set_id, int64 access_hash,
string name); string name);
void load_special_sticker_set_info_from_binlog(SpecialStickerSet &sticker_set); void load_special_sticker_set_info_from_binlog(SpecialStickerSet &sticker_set);
void load_special_sticker_set_by_type(const SpecialStickerSetType &type); void load_special_sticker_set_by_type(SpecialStickerSetType type);
void load_special_sticker_set(SpecialStickerSet &sticker_set); void load_special_sticker_set(SpecialStickerSet &sticker_set);
void reload_special_sticker_set(SpecialStickerSet &sticker_set); void reload_special_sticker_set_by_type(SpecialStickerSetType type, bool is_recursive = false);
void reload_special_sticker_set(SpecialStickerSet &sticker_set, int32 hash);
static void add_sticker_thumbnail(Sticker *s, PhotoSize thumbnail); static void add_sticker_thumbnail(Sticker *s, PhotoSize thumbnail);
@ -786,7 +787,7 @@ class StickersManager final : public Actor {
int32 recent_stickers_limit_ = 200; int32 recent_stickers_limit_ = 200;
int32 favorite_stickers_limit_ = 5; int32 favorite_stickers_limit_ = 5;
std::unordered_map<string, SpecialStickerSet> special_sticker_sets_; std::unordered_map<SpecialStickerSetType, SpecialStickerSet, SpecialStickerSetTypeHash> special_sticker_sets_;
struct StickerSetLoadRequest { struct StickerSetLoadRequest {
Promise<Unit> promise; Promise<Unit> promise;

View File

@ -8,6 +8,7 @@
#include "td/telegram/ChannelId.h" #include "td/telegram/ChannelId.h"
#include "td/telegram/ConfigManager.h" #include "td/telegram/ConfigManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/Td.h" #include "td/telegram/Td.h"
@ -70,6 +71,12 @@ SuggestedAction::SuggestedAction(const td_api::object_ptr<td_api::SuggestedActio
} }
break; break;
} }
case td_api::suggestedActionSetPassword::ID: {
auto action = static_cast<const td_api::suggestedActionSetPassword *>(suggested_action.get());
type_ = Type::SetPassword;
otherwise_relogin_days_ = action->authorization_delay_;
break;
}
default: default:
UNREACHABLE(); UNREACHABLE();
} }
@ -106,6 +113,8 @@ td_api::object_ptr<td_api::SuggestedAction> SuggestedAction::get_suggested_actio
return td_api::make_object<td_api::suggestedActionSeeTicksHint>(); return td_api::make_object<td_api::suggestedActionSeeTicksHint>();
case Type::ConvertToGigagroup: case Type::ConvertToGigagroup:
return td_api::make_object<td_api::suggestedActionConvertToBroadcastGroup>(dialog_id_.get_channel_id().get()); return td_api::make_object<td_api::suggestedActionConvertToBroadcastGroup>(dialog_id_.get_channel_id().get());
case Type::SetPassword:
return td_api::make_object<td_api::suggestedActionSetPassword>(otherwise_relogin_days_);
default: default:
UNREACHABLE(); UNREACHABLE();
return nullptr; return nullptr;
@ -166,6 +175,18 @@ void dismiss_suggested_action(SuggestedAction action, Promise<Unit> &&promise) {
case SuggestedAction::Type::ConvertToGigagroup: case SuggestedAction::Type::ConvertToGigagroup:
return send_closure_later(G()->contacts_manager(), &ContactsManager::dismiss_dialog_suggested_action, return send_closure_later(G()->contacts_manager(), &ContactsManager::dismiss_dialog_suggested_action,
std::move(action), std::move(promise)); std::move(action), std::move(promise));
case SuggestedAction::Type::SetPassword: {
if (action.otherwise_relogin_days_ <= 0) {
return promise.set_error(Status::Error(400, "Invalid authorization_delay specified"));
}
auto days = narrow_cast<int32>(G()->shared_config().get_option_integer("otherwise_relogin_days"));
if (days == action.otherwise_relogin_days_) {
vector<SuggestedAction> removed_actions{SuggestedAction{SuggestedAction::Type::SetPassword, DialogId(), days}};
send_closure(G()->td(), &Td::send_update, get_update_suggested_actions_object({}, removed_actions));
G()->shared_config().set_option_empty("otherwise_relogin_days");
}
return promise.set_value(Unit());
}
default: default:
UNREACHABLE(); UNREACHABLE();
return; return;

View File

@ -23,16 +23,19 @@ struct SuggestedAction {
CheckPhoneNumber, CheckPhoneNumber,
SeeTicksHint, SeeTicksHint,
ConvertToGigagroup, ConvertToGigagroup,
CheckPassword CheckPassword,
SetPassword
}; };
Type type_ = Type::Empty; Type type_ = Type::Empty;
DialogId dialog_id_; DialogId dialog_id_;
int32 otherwise_relogin_days_ = 0;
void init(Type type); void init(Type type);
SuggestedAction() = default; SuggestedAction() = default;
explicit SuggestedAction(Type type, DialogId dialog_id = DialogId()) : type_(type), dialog_id_(dialog_id) { explicit SuggestedAction(Type type, DialogId dialog_id = DialogId(), int32 otherwise_relogin_days = 0)
: type_(type), dialog_id_(dialog_id), otherwise_relogin_days_(otherwise_relogin_days) {
} }
explicit SuggestedAction(Slice action_str); explicit SuggestedAction(Slice action_str);

View File

@ -905,24 +905,6 @@ class GetGroupsInCommonRequest final : public RequestActor<> {
} }
}; };
class GetCreatedPublicChatsRequest final : public RequestActor<> {
vector<DialogId> dialog_ids_;
PublicDialogType type_;
void do_run(Promise<Unit> &&promise) final {
dialog_ids_ = td_->contacts_manager_->get_created_public_dialogs(type_, std::move(promise));
}
void do_send_result() final {
send_result(MessagesManager::get_chats_object(-1, dialog_ids_));
}
public:
GetCreatedPublicChatsRequest(ActorShared<Td> td, uint64 request_id, PublicDialogType type)
: RequestActor(std::move(td), request_id), type_(type) {
}
};
class GetSuitableDiscussionChatsRequest final : public RequestActor<> { class GetSuitableDiscussionChatsRequest final : public RequestActor<> {
vector<DialogId> dialog_ids_; vector<DialogId> dialog_ids_;
@ -1380,7 +1362,7 @@ class GetChatMessageCalendarRequest final : public RequestActor<> {
class SearchChatMessagesRequest final : public RequestActor<> { class SearchChatMessagesRequest final : public RequestActor<> {
DialogId dialog_id_; DialogId dialog_id_;
string query_; string query_;
td_api::object_ptr<td_api::MessageSender> sender_; td_api::object_ptr<td_api::MessageSender> sender_id_;
MessageId from_message_id_; MessageId from_message_id_;
int32 offset_; int32 offset_;
int32 limit_; int32 limit_;
@ -1391,9 +1373,9 @@ class SearchChatMessagesRequest final : public RequestActor<> {
std::pair<int32, vector<MessageId>> messages_; std::pair<int32, vector<MessageId>> messages_;
void do_run(Promise<Unit> &&promise) final { void do_run(Promise<Unit> &&promise) final {
messages_ = td_->messages_manager_->search_dialog_messages(dialog_id_, query_, sender_, from_message_id_, offset_, messages_ = td_->messages_manager_->search_dialog_messages(dialog_id_, query_, sender_id_, from_message_id_,
limit_, filter_, top_thread_message_id_, random_id_, offset_, limit_, filter_, top_thread_message_id_,
get_tries() == 3, std::move(promise)); random_id_, get_tries() == 3, std::move(promise));
} }
void do_send_result() final { void do_send_result() final {
@ -1412,12 +1394,12 @@ class SearchChatMessagesRequest final : public RequestActor<> {
public: public:
SearchChatMessagesRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, string query, SearchChatMessagesRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, string query,
td_api::object_ptr<td_api::MessageSender> sender, int64 from_message_id, int32 offset, td_api::object_ptr<td_api::MessageSender> sender_id, int64 from_message_id, int32 offset,
int32 limit, tl_object_ptr<td_api::SearchMessagesFilter> filter, int64 message_thread_id) int32 limit, tl_object_ptr<td_api::SearchMessagesFilter> filter, int64 message_thread_id)
: RequestActor(std::move(td), request_id) : RequestActor(std::move(td), request_id)
, dialog_id_(dialog_id) , dialog_id_(dialog_id)
, query_(std::move(query)) , query_(std::move(query))
, sender_(std::move(sender)) , sender_id_(std::move(sender_id))
, from_message_id_(from_message_id) , from_message_id_(from_message_id)
, offset_(offset) , offset_(offset)
, limit_(limit) , limit_(limit)
@ -2710,7 +2692,8 @@ Td::Td(unique_ptr<TdCallback> callback, Options options)
: callback_(std::move(callback)), td_options_(std::move(options)) { : callback_(std::move(callback)), td_options_(std::move(options)) {
CHECK(callback_ != nullptr); CHECK(callback_ != nullptr);
LOG(INFO) << "Create Td with layer " << MTPROTO_LAYER << ", database version " << current_db_version() LOG(INFO) << "Create Td with layer " << MTPROTO_LAYER << ", database version " << current_db_version()
<< " and version " << static_cast<int32>(Version::Next) - 1; << " and version " << static_cast<int32>(Version::Next) - 1 << " on "
<< Scheduler::instance()->sched_count() << " threads";
} }
Td::~Td() = default; Td::~Td() = default;
@ -3281,7 +3264,7 @@ bool Td::is_internal_config_option(Slice name) {
case 'n': case 'n':
return name == "notification_cloud_delay_ms" || name == "notification_default_delay_ms"; return name == "notification_cloud_delay_ms" || name == "notification_default_delay_ms";
case 'o': case 'o':
return name == "online_update_period_ms" || name == "online_cloud_timeout_ms"; return name == "online_update_period_ms" || name == "online_cloud_timeout_ms" || name == "otherwise_relogin_days";
case 'r': case 'r':
return name == "revoke_pm_inbox" || name == "revoke_time_limit" || name == "revoke_pm_time_limit" || return name == "revoke_pm_inbox" || name == "revoke_time_limit" || name == "revoke_pm_time_limit" ||
name == "rating_e_decay" || name == "recent_stickers_limit"; name == "rating_e_decay" || name == "recent_stickers_limit";
@ -3324,6 +3307,13 @@ void Td::on_config_option_updated(const string &name) {
stickers_manager_->on_update_disable_animated_emojis(); stickers_manager_->on_update_disable_animated_emojis();
} else if (name == "my_id") { } else if (name == "my_id") {
G()->set_my_id(G()->shared_config().get_option_integer(name)); G()->set_my_id(G()->shared_config().get_option_integer(name));
} else if (name == "otherwise_relogin_days") {
auto days = narrow_cast<int32>(G()->shared_config().get_option_integer(name));
if (days > 0) {
vector<SuggestedAction> added_actions{SuggestedAction{SuggestedAction::Type::SetPassword, DialogId(), days}};
send_closure(G()->td(), &Td::send_update, get_update_suggested_actions_object(added_actions, {}));
}
return;
} else if (name == "session_count") { } else if (name == "session_count") {
G()->net_query_dispatcher().update_session_count(); G()->net_query_dispatcher().update_session_count();
} else if (name == "use_pfs") { } else if (name == "use_pfs") {
@ -4255,7 +4245,7 @@ void Td::send_update(tl_object_ptr<td_api::Update> &&object) {
case td_api::updateUnreadMessageCount::ID / 2: case td_api::updateUnreadMessageCount::ID / 2:
case td_api::updateUnreadChatCount::ID / 2: case td_api::updateUnreadChatCount::ID / 2:
case td_api::updateChatOnlineMemberCount::ID / 2: case td_api::updateChatOnlineMemberCount::ID / 2:
case td_api::updateUserChatAction::ID / 2: case td_api::updateChatAction::ID / 2:
case td_api::updateChatFilters::ID / 2: case td_api::updateChatFilters::ID / 2:
case td_api::updateChatPosition::ID / 2: case td_api::updateChatPosition::ID / 2:
LOG(ERROR) << "Sending update: " << oneline(to_string(object)); LOG(ERROR) << "Sending update: " << oneline(to_string(object));
@ -4817,6 +4807,25 @@ void Td::on_request(uint64 id, const td_api::terminateAllOtherSessions &request)
terminate_all_other_sessions(this, std::move(promise)); terminate_all_other_sessions(this, std::move(promise));
} }
void Td::on_request(uint64 id, const td_api::toggleSessionCanAcceptCalls &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
toggle_session_can_accept_calls(this, request.session_id_, request.can_accept_calls_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::toggleSessionCanAcceptSecretChats &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
toggle_session_can_accept_secret_chats(this, request.session_id_, request.can_accept_secret_chats_,
std::move(promise));
}
void Td::on_request(uint64 id, const td_api::setInactiveSessionTtl &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
set_inactive_session_ttl_days(this, request.inactive_session_ttl_days_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getConnectedWebsites &request) { void Td::on_request(uint64 id, const td_api::getConnectedWebsites &request) {
CHECK_IS_USER(); CHECK_IS_USER();
CREATE_REQUEST_PROMISE(); CREATE_REQUEST_PROMISE();
@ -5238,7 +5247,8 @@ void Td::on_request(uint64 id, td_api::checkChatUsername &request) {
void Td::on_request(uint64 id, const td_api::getCreatedPublicChats &request) { void Td::on_request(uint64 id, const td_api::getCreatedPublicChats &request) {
CHECK_IS_USER(); CHECK_IS_USER();
CREATE_REQUEST(GetCreatedPublicChatsRequest, get_public_dialog_type(request.type_)); CREATE_REQUEST_PROMISE();
contacts_manager_->get_created_public_dialogs(get_public_dialog_type(request.type_), std::move(promise), false);
} }
void Td::on_request(uint64 id, const td_api::checkCreatedPublicChatsLimit &request) { void Td::on_request(uint64 id, const td_api::checkCreatedPublicChatsLimit &request) {
@ -5369,7 +5379,7 @@ void Td::on_request(uint64 id, td_api::getChatMessageCalendar &request) {
void Td::on_request(uint64 id, td_api::searchChatMessages &request) { void Td::on_request(uint64 id, td_api::searchChatMessages &request) {
CHECK_IS_USER(); CHECK_IS_USER();
CLEAN_INPUT_STRING(request.query_); CLEAN_INPUT_STRING(request.query_);
CREATE_REQUEST(SearchChatMessagesRequest, request.chat_id_, std::move(request.query_), std::move(request.sender_), CREATE_REQUEST(SearchChatMessagesRequest, request.chat_id_, std::move(request.query_), std::move(request.sender_id_),
request.from_message_id_, request.offset_, request.limit_, std::move(request.filter_), request.from_message_id_, request.offset_, request.limit_, std::move(request.filter_),
request.message_thread_id_); request.message_thread_id_);
} }
@ -5478,11 +5488,11 @@ void Td::on_request(uint64 id, const td_api::deleteMessages &request) {
request.revoke_, std::move(promise)); request.revoke_, std::move(promise));
} }
void Td::on_request(uint64 id, const td_api::deleteChatMessagesFromUser &request) { void Td::on_request(uint64 id, const td_api::deleteChatMessagesBySender &request) {
CHECK_IS_USER(); CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE(); CREATE_OK_REQUEST_PROMISE();
messages_manager_->delete_dialog_messages_from_user(DialogId(request.chat_id_), UserId(request.user_id_), TRY_RESULT_PROMISE(promise, sender_dialog_id, get_message_sender_dialog_id(this, request.sender_id_, false, false));
std::move(promise)); messages_manager_->delete_dialog_messages_by_sender(DialogId(request.chat_id_), sender_dialog_id, std::move(promise));
} }
void Td::on_request(uint64 id, const td_api::deleteChatMessagesByDate &request) { void Td::on_request(uint64 id, const td_api::deleteChatMessagesByDate &request) {
@ -5498,6 +5508,21 @@ void Td::on_request(uint64 id, const td_api::readAllChatMentions &request) {
messages_manager_->read_all_dialog_mentions(DialogId(request.chat_id_), std::move(promise)); messages_manager_->read_all_dialog_mentions(DialogId(request.chat_id_), std::move(promise));
} }
void Td::on_request(uint64 id, const td_api::getChatAvailableMessageSenders &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
messages_manager_->get_dialog_send_message_as_dialog_ids(DialogId(request.chat_id_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::setChatDefaultMessageSender &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
TRY_RESULT_PROMISE(promise, message_sender_dialog_id,
get_message_sender_dialog_id(this, request.default_message_sender_id_, true, false));
messages_manager_->set_dialog_default_send_message_as_dialog_id(DialogId(request.chat_id_), message_sender_dialog_id,
std::move(promise));
}
void Td::on_request(uint64 id, td_api::sendMessage &request) { void Td::on_request(uint64 id, td_api::sendMessage &request) {
auto r_sent_message = messages_manager_->send_message( auto r_sent_message = messages_manager_->send_message(
DialogId(request.chat_id_), MessageId(request.message_thread_id_), MessageId(request.reply_to_message_id_), DialogId(request.chat_id_), MessageId(request.message_thread_id_), MessageId(request.reply_to_message_id_),
@ -5561,7 +5586,7 @@ void Td::on_request(uint64 id, td_api::addLocalMessage &request) {
DialogId dialog_id(request.chat_id_); DialogId dialog_id(request.chat_id_);
auto r_new_message_id = messages_manager_->add_local_message( auto r_new_message_id = messages_manager_->add_local_message(
dialog_id, std::move(request.sender_), MessageId(request.reply_to_message_id_), request.disable_notification_, dialog_id, std::move(request.sender_id_), MessageId(request.reply_to_message_id_), request.disable_notification_,
std::move(request.input_message_content_)); std::move(request.input_message_content_));
if (r_new_message_id.is_error()) { if (r_new_message_id.is_error()) {
return send_closure(actor_id(this), &Td::send_error, id, r_new_message_id.move_as_error()); return send_closure(actor_id(this), &Td::send_error, id, r_new_message_id.move_as_error());
@ -6173,6 +6198,13 @@ void Td::on_request(uint64 id, td_api::setChatDraftMessage &request) {
std::move(request.draft_message_))); std::move(request.draft_message_)));
} }
void Td::on_request(uint64 id, const td_api::toggleChatHasProtectedContent &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
messages_manager_->toggle_dialog_has_protected_content(DialogId(request.chat_id_), request.has_protected_content_,
std::move(promise));
}
void Td::on_request(uint64 id, const td_api::toggleChatIsPinned &request) { void Td::on_request(uint64 id, const td_api::toggleChatIsPinned &request) {
CHECK_IS_USER(); CHECK_IS_USER();
answer_ok_query(id, messages_manager_->toggle_dialog_is_pinned(DialogListId(request.chat_list_), answer_ok_query(id, messages_manager_->toggle_dialog_is_pinned(DialogListId(request.chat_list_),
@ -6187,7 +6219,7 @@ void Td::on_request(uint64 id, const td_api::toggleChatIsMarkedAsUnread &request
void Td::on_request(uint64 id, const td_api::toggleMessageSenderIsBlocked &request) { void Td::on_request(uint64 id, const td_api::toggleMessageSenderIsBlocked &request) {
CHECK_IS_USER(); CHECK_IS_USER();
answer_ok_query(id, messages_manager_->toggle_message_sender_is_blocked(request.sender_, request.is_blocked_)); answer_ok_query(id, messages_manager_->toggle_message_sender_is_blocked(request.sender_id_, request.is_blocked_));
} }
void Td::on_request(uint64 id, const td_api::toggleChatDefaultDisableNotification &request) { void Td::on_request(uint64 id, const td_api::toggleChatDefaultDisableNotification &request) {
@ -6419,15 +6451,17 @@ void Td::on_request(uint64 id, td_api::getChatJoinRequests &request) {
std::move(request.offset_request_), request.limit_, std::move(promise)); std::move(request.offset_request_), request.limit_, std::move(promise));
} }
void Td::on_request(uint64 id, const td_api::approveChatJoinRequest &request) { void Td::on_request(uint64 id, const td_api::processChatJoinRequest &request) {
CREATE_OK_REQUEST_PROMISE(); CREATE_OK_REQUEST_PROMISE();
contacts_manager_->process_dialog_join_requests(DialogId(request.chat_id_), UserId(request.user_id_), true, contacts_manager_->process_dialog_join_request(DialogId(request.chat_id_), UserId(request.user_id_), request.approve_,
std::move(promise)); std::move(promise));
} }
void Td::on_request(uint64 id, const td_api::declineChatJoinRequest &request) { void Td::on_request(uint64 id, td_api::processChatJoinRequests &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.invite_link_);
CREATE_OK_REQUEST_PROMISE(); CREATE_OK_REQUEST_PROMISE();
contacts_manager_->process_dialog_join_requests(DialogId(request.chat_id_), UserId(request.user_id_), false, contacts_manager_->process_dialog_join_requests(DialogId(request.chat_id_), request.invite_link_, request.approve_,
std::move(promise)); std::move(promise));
} }
@ -6856,7 +6890,7 @@ void Td::on_request(uint64 id, const td_api::toggleSupergroupIsBroadcastGroup &r
void Td::on_request(uint64 id, const td_api::reportSupergroupSpam &request) { void Td::on_request(uint64 id, const td_api::reportSupergroupSpam &request) {
CHECK_IS_USER(); CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE(); CREATE_OK_REQUEST_PROMISE();
contacts_manager_->report_channel_spam(ChannelId(request.supergroup_id_), UserId(request.user_id_), contacts_manager_->report_channel_spam(ChannelId(request.supergroup_id_),
MessagesManager::get_message_ids(request.message_ids_), std::move(promise)); MessagesManager::get_message_ids(request.message_ids_), std::move(promise));
} }

View File

@ -259,7 +259,7 @@ class Td final : public Actor {
static td_api::object_ptr<td_api::Object> static_request(td_api::object_ptr<td_api::Function> function); static td_api::object_ptr<td_api::Object> static_request(td_api::object_ptr<td_api::Function> function);
private: private:
static constexpr const char *TDLIB_VERSION = "1.7.9"; static constexpr const char *TDLIB_VERSION = "1.7.10";
static constexpr int64 ONLINE_ALARM_ID = 0; static constexpr int64 ONLINE_ALARM_ID = 0;
static constexpr int64 PING_SERVER_ALARM_ID = -1; static constexpr int64 PING_SERVER_ALARM_ID = -1;
static constexpr int32 PING_SERVER_TIMEOUT = 300; static constexpr int32 PING_SERVER_TIMEOUT = 300;
@ -489,6 +489,12 @@ class Td final : public Actor {
void on_request(uint64 id, const td_api::terminateAllOtherSessions &request); void on_request(uint64 id, const td_api::terminateAllOtherSessions &request);
void on_request(uint64 id, const td_api::toggleSessionCanAcceptCalls &request);
void on_request(uint64 id, const td_api::toggleSessionCanAcceptSecretChats &request);
void on_request(uint64 id, const td_api::setInactiveSessionTtl &request);
void on_request(uint64 id, const td_api::getConnectedWebsites &request); void on_request(uint64 id, const td_api::getConnectedWebsites &request);
void on_request(uint64 id, const td_api::disconnectWebsite &request); void on_request(uint64 id, const td_api::disconnectWebsite &request);
@ -659,12 +665,16 @@ class Td final : public Actor {
void on_request(uint64 id, const td_api::deleteMessages &request); void on_request(uint64 id, const td_api::deleteMessages &request);
void on_request(uint64 id, const td_api::deleteChatMessagesFromUser &request); void on_request(uint64 id, const td_api::deleteChatMessagesBySender &request);
void on_request(uint64 id, const td_api::deleteChatMessagesByDate &request); void on_request(uint64 id, const td_api::deleteChatMessagesByDate &request);
void on_request(uint64 id, const td_api::readAllChatMentions &request); void on_request(uint64 id, const td_api::readAllChatMentions &request);
void on_request(uint64 id, const td_api::getChatAvailableMessageSenders &request);
void on_request(uint64 id, const td_api::setChatDefaultMessageSender &request);
void on_request(uint64 id, td_api::sendMessage &request); void on_request(uint64 id, td_api::sendMessage &request);
void on_request(uint64 id, td_api::sendMessageAlbum &request); void on_request(uint64 id, td_api::sendMessageAlbum &request);
@ -829,6 +839,8 @@ class Td final : public Actor {
void on_request(uint64 id, td_api::setChatDraftMessage &request); void on_request(uint64 id, td_api::setChatDraftMessage &request);
void on_request(uint64 id, const td_api::toggleChatHasProtectedContent &request);
void on_request(uint64 id, const td_api::toggleChatIsPinned &request); void on_request(uint64 id, const td_api::toggleChatIsPinned &request);
void on_request(uint64 id, const td_api::toggleChatIsMarkedAsUnread &request); void on_request(uint64 id, const td_api::toggleChatIsMarkedAsUnread &request);
@ -893,9 +905,9 @@ class Td final : public Actor {
void on_request(uint64 id, td_api::getChatJoinRequests &request); void on_request(uint64 id, td_api::getChatJoinRequests &request);
void on_request(uint64 id, const td_api::approveChatJoinRequest &request); void on_request(uint64 id, const td_api::processChatJoinRequest &request);
void on_request(uint64 id, const td_api::declineChatJoinRequest &request); void on_request(uint64 id, td_api::processChatJoinRequests &request);
void on_request(uint64 id, td_api::revokeChatInviteLink &request); void on_request(uint64 id, td_api::revokeChatInviteLink &request);

View File

@ -100,7 +100,7 @@ Status init_binlog(Binlog &binlog, string path, BinlogKeyValue<Binlog> &binlog_p
case LogEvent::HandlerType::SendInlineQueryResultMessage: case LogEvent::HandlerType::SendInlineQueryResultMessage:
case LogEvent::HandlerType::DeleteDialogHistoryOnServer: case LogEvent::HandlerType::DeleteDialogHistoryOnServer:
case LogEvent::HandlerType::ReadAllDialogMentionsOnServer: case LogEvent::HandlerType::ReadAllDialogMentionsOnServer:
case LogEvent::HandlerType::DeleteAllChannelMessagesFromUserOnServer: case LogEvent::HandlerType::DeleteAllChannelMessagesFromSenderOnServer:
case LogEvent::HandlerType::ToggleDialogIsPinnedOnServer: case LogEvent::HandlerType::ToggleDialogIsPinnedOnServer:
case LogEvent::HandlerType::ReorderPinnedDialogsOnServer: case LogEvent::HandlerType::ReorderPinnedDialogsOnServer:
case LogEvent::HandlerType::SaveDialogDraftMessageOnServer: case LogEvent::HandlerType::SaveDialogDraftMessageOnServer:

View File

@ -536,6 +536,24 @@ bool UpdatesManager::is_acceptable_message_entities(
return true; return true;
} }
bool UpdatesManager::is_acceptable_reply_markup(const tl_object_ptr<telegram_api::ReplyMarkup> &reply_markup) const {
if (reply_markup == nullptr || reply_markup->get_id() != telegram_api::replyInlineMarkup::ID) {
return true;
}
for (const auto &row : static_cast<const telegram_api::replyInlineMarkup *>(reply_markup.get())->rows_) {
for (const auto &button : row->buttons_) {
if (button->get_id() == telegram_api::keyboardButtonUserProfile::ID) {
auto user_profile_button = static_cast<const telegram_api::keyboardButtonUserProfile *>(button.get());
UserId user_id(user_profile_button->user_id_);
if (!is_acceptable_user(user_id) || !td_->contacts_manager_->have_input_user(user_id)) {
return false;
}
}
}
}
return true;
}
bool UpdatesManager::is_acceptable_message_reply_header( bool UpdatesManager::is_acceptable_message_reply_header(
const telegram_api::object_ptr<telegram_api::messageReplyHeader> &header) const { const telegram_api::object_ptr<telegram_api::messageReplyHeader> &header) const {
if (header == nullptr) { if (header == nullptr) {
@ -872,7 +890,7 @@ void UpdatesManager::on_get_updates(tl_object_ptr<telegram_api::Updates> &&updat
auto message = make_tl_object<telegram_api::message>( auto message = make_tl_object<telegram_api::message>(
update->flags_, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, update->flags_, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, update->id_, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, update->id_,
make_tl_object<telegram_api::peerUser>(from_id), make_tl_object<telegram_api::peerUser>(update->user_id_), make_tl_object<telegram_api::peerUser>(from_id), make_tl_object<telegram_api::peerUser>(update->user_id_),
std::move(update->fwd_from_), update->via_bot_id_, std::move(update->reply_to_), update->date_, std::move(update->fwd_from_), update->via_bot_id_, std::move(update->reply_to_), update->date_,
update->message_, nullptr, nullptr, std::move(update->entities_), 0, 0, nullptr, 0, string(), 0, Auto(), update->message_, nullptr, nullptr, std::move(update->entities_), 0, 0, nullptr, 0, string(), 0, Auto(),
@ -896,7 +914,7 @@ void UpdatesManager::on_get_updates(tl_object_ptr<telegram_api::Updates> &&updat
update->flags_ |= MessagesManager::MESSAGE_FLAG_HAS_FROM_ID; update->flags_ |= MessagesManager::MESSAGE_FLAG_HAS_FROM_ID;
auto message = make_tl_object<telegram_api::message>( auto message = make_tl_object<telegram_api::message>(
update->flags_, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, update->flags_, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, update->id_, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, update->id_,
make_tl_object<telegram_api::peerUser>(update->from_id_), make_tl_object<telegram_api::peerUser>(update->from_id_),
make_tl_object<telegram_api::peerChat>(update->chat_id_), std::move(update->fwd_from_), update->via_bot_id_, make_tl_object<telegram_api::peerChat>(update->chat_id_), std::move(update->fwd_from_), update->via_bot_id_,
std::move(update->reply_to_), update->date_, update->message_, nullptr, nullptr, std::move(update->entities_), std::move(update->reply_to_), update->date_, update->message_, nullptr, nullptr, std::move(update->entities_),
@ -2495,7 +2513,7 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateServiceNotifica
} }
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChat> update, Promise<Unit> &&promise) { void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChat> update, Promise<Unit> &&promise) {
// nothing to do td_->messages_manager_->on_dialog_info_full_invalidated(DialogId(ChatId(update->chat_id_)));
promise.set_value(Unit()); promise.set_value(Unit());
} }
@ -2832,15 +2850,14 @@ int32 UpdatesManager::get_update_qts(const telegram_api::Update *update) {
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateUserTyping> update, Promise<Unit> &&promise) { void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateUserTyping> update, Promise<Unit> &&promise) {
DialogId dialog_id(UserId(update->user_id_)); DialogId dialog_id(UserId(update->user_id_));
td_->messages_manager_->on_user_dialog_action(dialog_id, MessageId(), dialog_id, td_->messages_manager_->on_dialog_action(dialog_id, MessageId(), dialog_id, DialogAction(std::move(update->action_)),
DialogAction(std::move(update->action_)), get_short_update_date()); get_short_update_date());
promise.set_value(Unit()); promise.set_value(Unit());
} }
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChatUserTyping> update, Promise<Unit> &&promise) { void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChatUserTyping> update, Promise<Unit> &&promise) {
td_->messages_manager_->on_user_dialog_action(DialogId(ChatId(update->chat_id_)), MessageId(), td_->messages_manager_->on_dialog_action(DialogId(ChatId(update->chat_id_)), MessageId(), DialogId(update->from_id_),
DialogId(update->from_id_), DialogAction(std::move(update->action_)), DialogAction(std::move(update->action_)), get_short_update_date());
get_short_update_date());
promise.set_value(Unit()); promise.set_value(Unit());
} }
@ -2849,7 +2866,7 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannelUserTypi
if ((update->flags_ & telegram_api::updateChannelUserTyping::TOP_MSG_ID_MASK) != 0) { if ((update->flags_ & telegram_api::updateChannelUserTyping::TOP_MSG_ID_MASK) != 0) {
top_thread_message_id = MessageId(ServerMessageId(update->top_msg_id_)); top_thread_message_id = MessageId(ServerMessageId(update->top_msg_id_));
} }
td_->messages_manager_->on_user_dialog_action(DialogId(ChannelId(update->channel_id_)), top_thread_message_id, td_->messages_manager_->on_dialog_action(DialogId(ChannelId(update->channel_id_)), top_thread_message_id,
DialogId(update->from_id_), DialogAction(std::move(update->action_)), DialogId(update->from_id_), DialogAction(std::move(update->action_)),
get_short_update_date()); get_short_update_date());
promise.set_value(Unit()); promise.set_value(Unit());
@ -2858,7 +2875,7 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannelUserTypi
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateEncryptedChatTyping> update, Promise<Unit> &&promise) { void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateEncryptedChatTyping> update, Promise<Unit> &&promise) {
SecretChatId secret_chat_id(update->chat_id_); SecretChatId secret_chat_id(update->chat_id_);
UserId user_id = td_->contacts_manager_->get_secret_chat_user_id(secret_chat_id); UserId user_id = td_->contacts_manager_->get_secret_chat_user_id(secret_chat_id);
td_->messages_manager_->on_user_dialog_action(DialogId(secret_chat_id), MessageId(), DialogId(user_id), td_->messages_manager_->on_dialog_action(DialogId(secret_chat_id), MessageId(), DialogId(user_id),
DialogAction::get_typing_action(), get_short_update_date()); DialogAction::get_typing_action(), get_short_update_date());
promise.set_value(Unit()); promise.set_value(Unit());
} }

View File

@ -356,6 +356,8 @@ class UpdatesManager final : public Actor {
bool is_acceptable_message_entities(const vector<tl_object_ptr<telegram_api::MessageEntity>> &message_entities) const; bool is_acceptable_message_entities(const vector<tl_object_ptr<telegram_api::MessageEntity>> &message_entities) const;
bool is_acceptable_reply_markup(const tl_object_ptr<telegram_api::ReplyMarkup> &reply_markup) const;
bool is_acceptable_message_reply_header( bool is_acceptable_message_reply_header(
const telegram_api::object_ptr<telegram_api::messageReplyHeader> &header) const; const telegram_api::object_ptr<telegram_api::messageReplyHeader> &header) const;

View File

@ -10,7 +10,7 @@
namespace td { namespace td {
constexpr int32 MTPROTO_LAYER = 134; constexpr int32 MTPROTO_LAYER = 135;
enum class Version : int32 { enum class Version : int32 {
Initial, // 0 Initial, // 0
@ -48,6 +48,7 @@ enum class Version : int32 {
RemovePhotoVolumeAndLocalId, RemovePhotoVolumeAndLocalId,
Support64BitIds, Support64BitIds,
AddInviteLinksRequiringApproval, AddInviteLinksRequiringApproval,
AddKeyboardButtonFlags, // 35
Next Next
}; };

View File

@ -241,6 +241,8 @@ class CliClient final : public Actor {
std::unordered_map<int64, User> users_; std::unordered_map<int64, User> users_;
std::unordered_map<string, int64> username_to_user_id_; std::unordered_map<string, int64> username_to_user_id_;
vector<string> authentication_tokens_;
void register_user(const td_api::user &user) { void register_user(const td_api::user &user) {
User &new_user = users_[user.id_]; User &new_user = users_[user.id_];
new_user.first_name = user.first_name_; new_user.first_name = user.first_name_;
@ -280,6 +282,10 @@ class CliClient final : public Actor {
my_id_ = static_cast<const td_api::optionValueInteger *>(option.value_.get())->value_; my_id_ = static_cast<const td_api::optionValueInteger *>(option.value_.get())->value_;
LOG(INFO) << "Set my user identifier to " << my_id_; LOG(INFO) << "Set my user identifier to " << my_id_;
} }
if (option.name_ == "authentication_token" && option.value_->get_id() == td_api::optionValueString::ID) {
authentication_tokens_.insert(authentication_tokens_.begin(),
static_cast<const td_api::optionValueString *>(option.value_.get())->value_);
}
} }
int64 get_history_chat_id_ = 0; int64 get_history_chat_id_ = 0;
@ -1402,6 +1408,9 @@ class CliClient final : public Actor {
if (begins_with(action, "giga")) { if (begins_with(action, "giga")) {
return td_api::make_object<td_api::suggestedActionConvertToBroadcastGroup>(as_supergroup_id(action.substr(4))); return td_api::make_object<td_api::suggestedActionConvertToBroadcastGroup>(as_supergroup_id(action.substr(4)));
} }
if (begins_with(action, "spass")) {
return td_api::make_object<td_api::suggestedActionSetPassword>(to_integer<int32>(action.substr(5)));
}
return nullptr; return nullptr;
} }
@ -1577,6 +1586,11 @@ class CliClient final : public Actor {
return td_api::make_object<td_api::backgroundTypeFill>(get_background_fill(std::move(colors))); return td_api::make_object<td_api::backgroundTypeFill>(get_background_fill(std::move(colors)));
} }
td_api::object_ptr<td_api::phoneNumberAuthenticationSettings> get_phone_number_authentication_settings() const {
return td_api::make_object<td_api::phoneNumberAuthenticationSettings>(false, true, false, false,
vector<string>(authentication_tokens_));
}
static td_api::object_ptr<td_api::Object> execute(td_api::object_ptr<td_api::Function> f) { static td_api::object_ptr<td_api::Object> execute(td_api::object_ptr<td_api::Function> f) {
if (combined_log.get_first_verbosity_level() < get_log_tag_verbosity_level("td_requests")) { if (combined_log.get_first_verbosity_level() < get_log_tag_verbosity_level("td_requests")) {
LOG(ERROR) << "Execute request: " << to_string(f); LOG(ERROR) << "Execute request: " << to_string(f);
@ -1642,8 +1656,9 @@ class CliClient final : public Actor {
if (op == "gas") { if (op == "gas") {
send_request(td_api::make_object<td_api::getAuthorizationState>()); send_request(td_api::make_object<td_api::getAuthorizationState>());
} else if (op == "sap") { } else if (op == "sap" || op == "sapn") {
send_request(td_api::make_object<td_api::setAuthenticationPhoneNumber>(args, nullptr)); send_request(
td_api::make_object<td_api::setAuthenticationPhoneNumber>(args, get_phone_number_authentication_settings()));
} else if (op == "rac") { } else if (op == "rac") {
send_request(td_api::make_object<td_api::resendAuthenticationCode>()); send_request(td_api::make_object<td_api::resendAuthenticationCode>());
} else if (op == "cdek" || op == "CheckDatabaseEncryptionKey") { } else if (op == "cdek" || op == "CheckDatabaseEncryptionKey") {
@ -2073,10 +2088,12 @@ class CliClient final : public Actor {
} else if (op == "SMU" || op == "SMC") { } else if (op == "SMU" || op == "SMC") {
string chat_id; string chat_id;
string sender_id; string sender_id;
string from_message_id;
string limit; string limit;
get_args(args, chat_id, sender_id, limit); get_args(args, chat_id, sender_id, from_message_id, limit);
send_request(td_api::make_object<td_api::searchChatMessages>( send_request(td_api::make_object<td_api::searchChatMessages>(
as_chat_id(chat_id), "", as_message_sender(sender_id), 0, 0, as_limit(limit), nullptr, 0)); as_chat_id(chat_id), "", as_message_sender(sender_id), as_message_id(from_message_id), 0, as_limit(limit),
nullptr, 0));
} else if (op == "SM") { } else if (op == "SM") {
string chat_id; string chat_id;
string filter; string filter;
@ -2243,12 +2260,24 @@ class CliClient final : public Actor {
td_api::make_object<td_api::setAccountTtl>(td_api::make_object<td_api::accountTtl>(to_integer<int32>(args)))); td_api::make_object<td_api::setAccountTtl>(td_api::make_object<td_api::accountTtl>(to_integer<int32>(args))));
} else if (op == "gattl") { } else if (op == "gattl") {
send_request(td_api::make_object<td_api::getAccountTtl>()); send_request(td_api::make_object<td_api::getAccountTtl>());
} else if (op == "GetActiveSessions") { } else if (op == "GetActiveSessions" || op == "devices" || op == "sessions") {
send_request(td_api::make_object<td_api::getActiveSessions>()); send_request(td_api::make_object<td_api::getActiveSessions>());
} else if (op == "TerminateSession") { } else if (op == "TerminateSession") {
send_request(td_api::make_object<td_api::terminateSession>(to_integer<int64>(args))); send_request(td_api::make_object<td_api::terminateSession>(to_integer<int64>(args)));
} else if (op == "TerminateAllOtherSessions") { } else if (op == "TerminateAllOtherSessions") {
send_request(td_api::make_object<td_api::terminateAllOtherSessions>()); send_request(td_api::make_object<td_api::terminateAllOtherSessions>());
} else if (op == "tscac") {
int64 session_id;
bool can_accept_calls;
get_args(args, session_id, can_accept_calls);
send_request(td_api::make_object<td_api::toggleSessionCanAcceptCalls>(session_id, can_accept_calls));
} else if (op == "tscasc") {
int64 session_id;
bool can_accept_secret_chats;
get_args(args, session_id, can_accept_secret_chats);
send_request(td_api::make_object<td_api::toggleSessionCanAcceptSecretChats>(session_id, can_accept_secret_chats));
} else if (op == "sist") {
send_request(td_api::make_object<td_api::setInactiveSessionTtl>(to_integer<int32>(args)));
} else if (op == "gcw") { } else if (op == "gcw") {
send_request(td_api::make_object<td_api::getConnectedWebsites>()); send_request(td_api::make_object<td_api::getConnectedWebsites>());
} else if (op == "dw") { } else if (op == "dw") {
@ -3037,16 +3066,19 @@ class CliClient final : public Actor {
as_chat_id(chat_id), invite_link, query, as_chat_id(chat_id), invite_link, query,
td_api::make_object<td_api::chatJoinRequest>(as_user_id(offset_user_id), offset_date, string()), td_api::make_object<td_api::chatJoinRequest>(as_user_id(offset_user_id), offset_date, string()),
as_limit(limit))); as_limit(limit)));
} else if (op == "acjr") { } else if (op == "pcjr") {
string chat_id; string chat_id;
string user_id; string user_id;
get_args(args, chat_id, user_id); bool approve;
send_request(td_api::make_object<td_api::approveChatJoinRequest>(as_chat_id(chat_id), as_user_id(user_id))); get_args(args, chat_id, user_id, approve);
} else if (op == "dcjr") { send_request(
td_api::make_object<td_api::processChatJoinRequest>(as_chat_id(chat_id), as_user_id(user_id), approve));
} else if (op == "pcjrs") {
string chat_id; string chat_id;
string user_id; string invite_link;
get_args(args, chat_id, user_id); bool approve;
send_request(td_api::make_object<td_api::declineChatJoinRequest>(as_chat_id(chat_id), as_user_id(user_id))); get_args(args, chat_id, invite_link, approve);
send_request(td_api::make_object<td_api::processChatJoinRequests>(as_chat_id(chat_id), invite_link, approve));
} else if (op == "drcil") { } else if (op == "drcil") {
string chat_id; string chat_id;
string invite_link; string invite_link;
@ -3163,6 +3195,12 @@ class CliClient final : public Actor {
as_chat_id(chat_id), as_message_thread_id(message_thread_id), std::move(draft_message))); as_chat_id(chat_id), as_message_thread_id(message_thread_id), std::move(draft_message)));
} else if (op == "cadm") { } else if (op == "cadm") {
send_request(td_api::make_object<td_api::clearAllDraftMessages>()); send_request(td_api::make_object<td_api::clearAllDraftMessages>());
} else if (op == "tcasc") {
string chat_id;
bool has_protected_content;
get_args(args, chat_id, has_protected_content);
send_request(
td_api::make_object<td_api::toggleChatHasProtectedContent>(as_chat_id(chat_id), has_protected_content));
} else if (op == "tcip" || op == "tcipa" || begins_with(op, "tcip-")) { } else if (op == "tcip" || op == "tcipa" || begins_with(op, "tcip-")) {
string chat_id; string chat_id;
bool is_pinned; bool is_pinned;
@ -3232,6 +3270,14 @@ class CliClient final : public Actor {
schedule_date_ = std::move(args); schedule_date_ = std::move(args);
} else if (op == "smti") { } else if (op == "smti") {
message_thread_id_ = std::move(args); message_thread_id_ = std::move(args);
} else if (op == "gcams") {
send_request(td_api::make_object<td_api::getChatAvailableMessageSenders>(as_chat_id(args)));
} else if (op == "scdms") {
string chat_id;
string sender_id;
get_args(args, chat_id, sender_id);
send_request(
td_api::make_object<td_api::setChatDefaultMessageSender>(as_chat_id(chat_id), as_message_sender(sender_id)));
} else if (op == "sm" || op == "sms" || op == "smr" || op == "smf") { } else if (op == "sm" || op == "sms" || op == "smr" || op == "smf") {
string chat_id; string chat_id;
string reply_to_message_id; string reply_to_message_id;
@ -3759,11 +3805,12 @@ class CliClient final : public Actor {
get_args(args, chat_id, min_date, max_date, revoke); get_args(args, chat_id, min_date, max_date, revoke);
send_request( send_request(
td_api::make_object<td_api::deleteChatMessagesByDate>(as_chat_id(chat_id), min_date, max_date, revoke)); td_api::make_object<td_api::deleteChatMessagesByDate>(as_chat_id(chat_id), min_date, max_date, revoke));
} else if (op == "dmfu") { } else if (op == "dcmbs") {
string chat_id; string chat_id;
string user_id; string sender_id;
get_args(args, chat_id, user_id); get_args(args, chat_id, sender_id);
send_request(td_api::make_object<td_api::deleteChatMessagesFromUser>(as_chat_id(chat_id), as_user_id(user_id))); send_request(
td_api::make_object<td_api::deleteChatMessagesBySender>(as_chat_id(chat_id), as_message_sender(sender_id)));
} else if (op == "cnbgc") { } else if (op == "cnbgc") {
string user_ids_string; string user_ids_string;
string title; string title;
@ -4326,13 +4373,12 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::getLoginUrl>(as_chat_id(chat_id), as_message_id(message_id), send_request(td_api::make_object<td_api::getLoginUrl>(as_chat_id(chat_id), as_message_id(message_id),
as_button_id(button_id), op == "glua")); as_button_id(button_id), op == "glua"));
} }
} else if (op == "rsgs" || op == "rchs") { } else if (op == "rsgs") {
string supergroup_id; string supergroup_id;
string user_id;
string message_ids; string message_ids;
get_args(args, supergroup_id, user_id, message_ids); get_args(args, supergroup_id, message_ids);
send_request(td_api::make_object<td_api::reportSupergroupSpam>(as_supergroup_id(supergroup_id), send_request(td_api::make_object<td_api::reportSupergroupSpam>(as_supergroup_id(supergroup_id),
as_user_id(user_id), as_message_ids(message_ids))); as_message_ids(message_ids)));
} else if (op == "gdiff") { } else if (op == "gdiff") {
send_request(td_api::make_object<td_api::testGetDifference>()); send_request(td_api::make_object<td_api::testGetDifference>());
} else if (op == "dproxy") { } else if (op == "dproxy") {

View File

@ -81,7 +81,7 @@ class LogEvent {
SendInlineQueryResultMessage = 0x108, SendInlineQueryResultMessage = 0x108,
DeleteDialogHistoryOnServer = 0x109, DeleteDialogHistoryOnServer = 0x109,
ReadAllDialogMentionsOnServer = 0x10a, ReadAllDialogMentionsOnServer = 0x10a,
DeleteAllChannelMessagesFromUserOnServer = 0x10b, DeleteAllChannelMessagesFromSenderOnServer = 0x10b,
ToggleDialogIsPinnedOnServer = 0x10c, ToggleDialogIsPinnedOnServer = 0x10c,
ReorderPinnedDialogsOnServer = 0x10d, ReorderPinnedDialogsOnServer = 0x10d,
SaveDialogDraftMessageOnServer = 0x10e, SaveDialogDraftMessageOnServer = 0x10e,

View File

@ -16,6 +16,7 @@
#include "td/utils/port/FileFd.h" #include "td/utils/port/FileFd.h"
#include "td/utils/port/path.h" #include "td/utils/port/path.h"
#include "td/utils/port/PollFlags.h" #include "td/utils/port/PollFlags.h"
#include "td/utils/port/sleep.h"
#include "td/utils/port/Stat.h" #include "td/utils/port/Stat.h"
#include "td/utils/Random.h" #include "td/utils/Random.h"
#include "td/utils/ScopeGuard.h" #include "td/utils/ScopeGuard.h"
@ -670,14 +671,19 @@ void Binlog::do_reindex() {
auto finish_time = Clocks::monotonic(); auto finish_time = Clocks::monotonic();
auto finish_size = fd_size_; auto finish_size = fd_size_;
auto finish_events = fd_events_; auto finish_events = fd_events_;
{ for (int left_tries = 10; left_tries > 0; left_tries--) {
auto r_stat = stat(path_); auto r_stat = stat(path_);
if (r_stat.is_error()) { if (r_stat.is_error()) {
if (left_tries != 1) {
usleep_for(200000 / left_tries);
continue;
}
LOG(FATAL) << "Failed to rename binlog of size " << fd_size_ << " to " << path_ << ": " << r_stat.error() LOG(FATAL) << "Failed to rename binlog of size " << fd_size_ << " to " << path_ << ": " << r_stat.error()
<< ". Old file size is " << detail::file_size(new_path); << ". Temp file size is " << detail::file_size(new_path) << ", new size " << detail::file_size(path_);
} }
LOG_CHECK(fd_size_ == r_stat.ok().size_) << fd_size_ << ' ' << r_stat.ok().size_ << ' ' LOG_CHECK(fd_size_ == r_stat.ok().size_) << fd_size_ << ' ' << r_stat.ok().size_ << ' '
<< detail::file_size(new_path) << ' ' << fd_events_ << ' ' << path_; << detail::file_size(new_path) << ' ' << fd_events_ << ' ' << path_;
break;
} }
auto ratio = static_cast<double>(start_size) / static_cast<double>(finish_size + 1); auto ratio = static_cast<double>(start_size) / static_cast<double>(finish_size + 1);

View File

@ -36,7 +36,7 @@ class HttpReader {
HttpReader &operator=(HttpReader &&other) = delete; HttpReader &operator=(HttpReader &&other) = delete;
~HttpReader() { ~HttpReader() {
if (!temp_file_.empty()) { if (!temp_file_.empty()) {
temp_file_.close(); clean_temporary_file();
} }
} }