Merge remote-tracking branch 'td/master'

This commit is contained in:
Andrea Cavalli 2021-11-05 16:11:03 +01:00
commit 9c9772868b
131 changed files with 3594 additions and 1339 deletions

View File

@ -6,7 +6,7 @@ if (POLICY CMP0065)
cmake_policy(SET CMP0065 NEW)
endif()
project(TDLib VERSION 1.7.8 LANGUAGES CXX C)
project(TDLib VERSION 1.7.9 LANGUAGES CXX C)
if (NOT DEFINED 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:
```
find_package(Td 1.7.8 REQUIRED)
find_package(Td 1.7.9 REQUIRED)
target_link_libraries(YourTarget PRIVATE Td::TdStatic)
```
See [example/cpp/CMakeLists.txt](https://github.com/tdlight-team/tdlight/tree/master/example/cpp/CMakeLists.txt).

View File

@ -43,7 +43,6 @@ class td::ActorTraits<TestActor> {
};
class CreateActorBench final : public td::Benchmark {
private:
td::ConcurrentScheduler scheduler_;
void start_up() final {

View File

@ -12,6 +12,7 @@
#include "td/actor/ConcurrentScheduler.h"
#include "td/utils/buffer.h"
#include "td/utils/BufferedFd.h"
#include "td/utils/logging.h"
#include "td/utils/port/IPAddress.h"
#include "td/utils/port/SocketFd.h"

View File

@ -13,6 +13,7 @@
#include "td/actor/ConcurrentScheduler.h"
#include "td/utils/buffer.h"
#include "td/utils/BufferedFd.h"
#include "td/utils/logging.h"
#include "td/utils/port/SocketFd.h"
#include "td/utils/Slice.h"

View File

@ -17,8 +17,6 @@
// TODO: all return values must be checked
#include <atomic>
#include <cstdlib>
#include <vector>
#if TD_PORT_POSIX
#include <pthread.h>

View File

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

View File

@ -34,13 +34,7 @@ namespace TdExample
private static Td.Client CreateTdClient()
{
Td.Client result = Td.Client.Create(new UpdateHandler());
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
result.Run();
}).Start();
return result;
return Td.Client.Create(new UpdateHandler());
}
private static void Print(string str)
@ -133,7 +127,6 @@ namespace TdExample
else if (_authorizationState is TdApi.AuthorizationStateClosed)
{
Print("Closed");
_client.Dispose(); // _client is closed and native resources can be disposed now
if (!_needQuit)
{
_client = CreateTdClient(); // recreate _client after previous has closed
@ -223,6 +216,11 @@ namespace TdExample
{
throw new System.IO.IOException("Write access to the current directory is required");
}
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
Td.Client.Run();
}).Start();
// create Td.Client
_client = CreateTdClient();

View File

@ -30,30 +30,23 @@ namespace TdApp
Td.Client.Execute(new TdApi.SetLogVerbosityLevel(0));
Td.Client.Execute(new TdApi.SetLogStream(new TdApi.LogStreamFile(Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "log"), 1 << 27, false)));
Td.Client.SetLogMessageCallback(100, LogMessageCallback);
System.Threading.Tasks.Task.Run(() =>
{
try
{
_client = Td.Client.Create(_handler);
var parameters = new TdApi.TdlibParameters();
parameters.DatabaseDirectory = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
parameters.UseSecretChats = true;
parameters.UseMessageDatabase = true;
parameters.ApiId = 94575;
parameters.ApiHash = "a3406de8d171bb422bb6ddf3bbd800e2";
parameters.SystemLanguageCode = "en";
parameters.DeviceModel = "Desktop";
parameters.ApplicationVersion = "1.0.0";
_client.Send(new TdApi.SetTdlibParameters(parameters), null);
_client.Send(new TdApi.CheckDatabaseEncryptionKey(), null);
_client.Run();
}
catch (Exception ex)
{
Print(ex.ToString());
}
Td.Client.Run();
});
_client = Td.Client.Create(_handler);
var parameters = new TdApi.TdlibParameters();
parameters.DatabaseDirectory = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
parameters.UseSecretChats = true;
parameters.UseMessageDatabase = true;
parameters.ApiId = 94575;
parameters.ApiHash = "a3406de8d171bb422bb6ddf3bbd800e2";
parameters.SystemLanguageCode = "en";
parameters.DeviceModel = "Desktop";
parameters.ApplicationVersion = "1.0.0";
_client.Send(new TdApi.SetTdlibParameters(parameters), null);
_client.Send(new TdApi.CheckDatabaseEncryptionKey(), null);
}
public void Print(String str)

View File

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

View File

@ -56,7 +56,7 @@ authenticationCodeTypeCall length:int32 = AuthenticationCodeType;
authenticationCodeTypeFlashCall pattern:string = AuthenticationCodeType;
//@description Information about the authentication code that was sent @phone_number A phone number that is being authenticated @type Describes the way the code was sent to the user @next_type Describes 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;
//@description Information about the email address authentication code that was sent @email_address_pattern Pattern of the email address to which an authentication code was sent @length Length of the code; 0 if unknown
@ -234,6 +234,10 @@ maskPointChin = MaskPoint;
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
closedVectorPath commands:vector<VectorPathCommand> = ClosedVectorPath;
@ -294,6 +298,12 @@ videoNote duration:int32 length:int32 minithumbnail:minithumbnail thumbnail:thum
//@waveform A waveform representation of the voice note in 5-bit format @mime_type MIME type of the file; as defined by the sender @voice File containing the voice note
voiceNote duration:int32 waveform:bytes mime_type:string voice:file = VoiceNote;
//@description Describes an animated representation of an emoji
//@sticker Animated sticker for the emoji
//@color_replacements List of colors to be replaced while the sticker is rendered
//@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;
//@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;
@ -471,7 +481,7 @@ chatPermissions can_send_messages:Bool can_send_media_messages:Bool can_send_pol
//@is_member True, if the user is a member of the chat
chatMemberStatusCreator custom_title:string is_anonymous:Bool is_member:Bool = ChatMemberStatus;
//@description The user is a member of the chat and has some additional privileges. In basic groups, administrators can edit and delete messages sent by others, add new members, ban unprivileged members, and manage voice chats. In supergroups and channels, there are more detailed options for administrator privileges
//@description The user is a member of the chat and has some additional privileges. In basic groups, administrators can edit and delete messages sent by others, add new members, ban unprivileged members, and manage video chats. In supergroups and channels, there are more detailed options for administrator privileges
//@custom_title A custom title of the administrator; 0-16 characters without emojis; applicable to supergroups only
//@can_be_edited True, if the current user can edit the administrator privileges for the called user
//@can_manage_chat True, if the administrator can get chat event log, get chat statistics, get message statistics in channels, get channel members, see anonymous administrators in supergroups and ignore slow mode. Implied by any other privilege; applicable to supergroups and channels only
@ -483,9 +493,9 @@ chatMemberStatusCreator custom_title:string is_anonymous:Bool is_member:Bool = C
//@can_restrict_members True, if the administrator can restrict, ban, or unban chat members; always true for channels
//@can_pin_messages True, if the administrator can pin messages; applicable to basic groups and supergroups only
//@can_promote_members True, if the administrator can add new administrators with a subset of their own privileges or demote administrators that were directly or indirectly promoted by them
//@can_manage_voice_chats True, if the administrator can manage voice chats
//@can_manage_video_chats True, if the administrator can manage video chats
//@is_anonymous True, if the administrator isn't shown in the chat member list and sends messages anonymously; applicable to supergroups only
chatMemberStatusAdministrator custom_title:string can_be_edited:Bool can_manage_chat:Bool can_change_info:Bool can_post_messages:Bool can_edit_messages:Bool can_delete_messages:Bool can_invite_users:Bool can_restrict_members:Bool can_pin_messages:Bool can_promote_members:Bool can_manage_voice_chats:Bool is_anonymous:Bool = ChatMemberStatus;
chatMemberStatusAdministrator custom_title:string can_be_edited:Bool can_manage_chat:Bool can_change_info:Bool can_post_messages:Bool can_edit_messages:Bool can_delete_messages:Bool can_invite_users:Bool can_restrict_members:Bool can_pin_messages:Bool can_promote_members:Bool can_manage_video_chats:Bool is_anonymous:Bool = ChatMemberStatus;
//@description The user is a member of the chat, without any additional privileges or restrictions
chatMemberStatusMember = ChatMemberStatus;
@ -499,12 +509,12 @@ chatMemberStatusRestricted is_member:Bool restricted_until_date:int32 permission
//@description The user or the chat is not a chat member
chatMemberStatusLeft = ChatMemberStatus;
//@description The user or the chat was banned (and hence is not a member of the chat). Implies the user can't return to the chat, view messages, or be used as a participant identifier to join a voice chat of the chat
//@description The user or the chat was banned (and hence is not a member of the chat). Implies the user can't return to the chat, view messages, or be used as a participant identifier to join a video chat of the chat
//@banned_until_date Point in time (Unix timestamp) when the user will be unbanned; 0 if never. If the user is banned for more than 366 days or for less than 30 seconds from the current time, the user is considered to be banned forever. Always 0 in basic groups
chatMemberStatusBanned banned_until_date:int32 = ChatMemberStatus;
//@description Information about a user or a chat as a member of another chat
//@description Describes a user or a chat as a member of another chat
//@member_id Identifier of the chat member. Currently, other chats can be only Left or Banned. Only supergroups and channels can have other chats as Left or Banned members and these chats must be supergroups or channels
//@inviter_user_id Identifier of a user that invited/promoted/banned this member in the chat; 0 if unknown
//@joined_chat_date Point in time (Unix timestamp) when the user joined the chat
@ -566,15 +576,20 @@ supergroupMembersFilterMention query:string message_thread_id:int53 = Supergroup
supergroupMembersFilterBots = SupergroupMembersFilter;
//@description Contains a chat invite link @invite_link Chat invite link @creator_user_id User identifier of an administrator created the link
//@description Contains a chat invite link
//@invite_link Chat invite link
//@name Name of the link
//@creator_user_id User identifier of an administrator created the link
//@date Point in time (Unix timestamp) when the link was created
//@edit_date Point in time (Unix timestamp) when the link was last edited; 0 if never or unknown
//@expire_date Point in time (Unix timestamp) when the link will expire; 0 if never
//@member_limit The maximum number of members, which can join the chat using the link simultaneously; 0 if not limited
//@member_limit The maximum number of members, which can join the chat using the link simultaneously; 0 if not limited. Always 0 if the link requires approval
//@member_count Number of chat members, which joined the chat using the link
//@is_primary True, if the link is primary. Primary invite link can't have expire date or usage limit. There is exactly one primary invite link for each administrator with can_invite_users right at a given time
//@pending_join_request_count Number of pending join requests created using this link
//@creates_join_request True, if the link only creates join request. If true, total number of joining members will be unlimited
//@is_primary True, if the link is primary. Primary invite link can't have name, expire date or usage limit. There is exactly one primary invite link for each administrator with can_invite_users right at a given time
//@is_revoked True, if the link was revoked
chatInviteLink invite_link:string creator_user_id:int53 date:int32 edit_date:int32 expire_date:int32 member_limit:int32 member_count:int32 is_primary:Bool is_revoked:Bool = ChatInviteLink;
chatInviteLink invite_link:string name:string creator_user_id:int53 date:int32 edit_date:int32 expire_date:int32 member_limit:int32 member_count:int32 pending_join_request_count:int32 creates_join_request:Bool is_primary:Bool is_revoked:Bool = ChatInviteLink;
//@description Contains a list of chat invite links @total_count Approximate total count of chat invite links found @invite_links List of invite links
chatInviteLinks total_count:int32 invite_links:vector<chatInviteLink> = ChatInviteLinks;
@ -588,8 +603,8 @@ chatInviteLinkCount user_id:int53 invite_link_count:int32 revoked_invite_link_co
//@description Contains a list of chat invite link counts @invite_link_counts List of invite linkcounts
chatInviteLinkCounts invite_link_counts:vector<chatInviteLinkCount> = ChatInviteLinkCounts;
//@description Describes a chat member joined a chat by an invite link @user_id User identifier @joined_chat_date Point in time (Unix timestamp) when the user joined the chat
chatInviteLinkMember user_id:int53 joined_chat_date:int32 = ChatInviteLinkMember;
//@description Describes a chat member joined a chat by an invite link @user_id User identifier @joined_chat_date Point in time (Unix timestamp) when the user joined the chat @approver_user_id User identifier of the chat administrator, approved user join request
chatInviteLinkMember user_id:int53 joined_chat_date:int32 approver_user_id:int53 = ChatInviteLinkMember;
//@description Contains a list of chat members joined a chat by an invite link @total_count Approximate total count of chat members found @members List of chat members, joined a chat by an invite link
chatInviteLinkMembers total_count:int32 members:vector<chatInviteLinkMember> = ChatInviteLinkMembers;
@ -597,13 +612,24 @@ chatInviteLinkMembers total_count:int32 members:vector<chatInviteLinkMember> = C
//@description Contains information about a chat invite link
//@chat_id Chat identifier of the invite link; 0 if the user has no access to the chat before joining
//@accessible_for If non-zero, the amount of time for which read access to the chat will remain available, in seconds
//@type Contains information about the type of the chat
//@type Type of the chat
//@title Title of the chat
//@photo Chat photo; may be null
//@param_description Chat description
//@member_count Number of members in the chat
//@member_user_ids User identifiers of some chat members that may be known to the current user
//@creates_join_request True, if the link only creates join request
//@is_public True, if the chat is a public supergroup or channel, i.e. it has a username or it is a location-based supergroup
chatInviteLinkInfo chat_id:int53 accessible_for:int32 type:ChatType title:string photo:chatPhotoInfo member_count:int32 member_user_ids:vector<int53> is_public:Bool = ChatInviteLinkInfo;
chatInviteLinkInfo chat_id:int53 accessible_for:int32 type:ChatType title:string photo:chatPhotoInfo description:string member_count:int32 member_user_ids:vector<int53> creates_join_request:Bool is_public:Bool = ChatInviteLinkInfo;
//@description Describes a user that sent a join request and waits for administrator approval @user_id User identifier @date Point in time (Unix timestamp) when the user sent the join request @bio A short bio of the user
chatJoinRequest user_id:int53 date:int32 bio:string = ChatJoinRequest;
//@description Contains a list of chat join requests @total_count Approximate total count of requests found @requests List of the requests
chatJoinRequests total_count:int32 requests:vector<chatJoinRequest> = ChatJoinRequests;
//@description Contains information about pending chat join requests @total_count Total number of pending join requests @user_ids Identifiers of users sent the newest pending join requests
chatJoinRequestsInfo total_count:int32 user_ids:vector<int53> = ChatJoinRequestsInfo;
//@description Represents a basic group of 0-200 users (must be upgraded to a supergroup to accommodate more than 200 users)
@ -745,7 +771,7 @@ messageReplyInfo reply_count:int32 recent_repliers:vector<MessageSender> last_re
//@description Contains information about interactions with a message
//@view_count Number of times the message was viewed
//@forward_count Number of times the message was forwarded
//@reply_info Contains information about direct or indirect replies to the message; may be null. Currently, available only in channels with a discussion supergroup and discussion supergroups for messages, which are not replies itself
//@reply_info Information about direct or indirect replies to the message; may be null. Currently, available only in channels with a discussion supergroup and discussion supergroups for messages, which are not replies itself
messageInteractionInfo view_count:int32 forward_count:int32 reply_info:messageReplyInfo = MessageInteractionInfo;
@ -763,8 +789,8 @@ messageSendingStateFailed error_code:int32 error_message:string can_retry:Bool r
//@id Message identifier; unique for the chat to which the message belongs
//@sender The sender of the message
//@chat_id Chat identifier
//@sending_state Information about the sending state of the message; may be null
//@scheduling_state Information about the scheduling 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
//@is_outgoing True, if the message is outgoing
//@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
@ -801,6 +827,18 @@ messages total_count:int32 messages:vector<message> = Messages;
//@description Contains a list of messages found by a search @total_count Approximate total count of messages found; -1 if unknown @messages List of messages @next_offset The offset for the next request. If empty, there are no more results
foundMessages total_count:int32 messages:vector<message> next_offset:string = FoundMessages;
//@description Contains information about a message in a specific position @position 0-based message position in the full list of suitable messages @message_id Message identifier @date Point in time (Unix timestamp) when the message was sent
messagePosition position:int32 message_id:int53 date:int32 = MessagePosition;
//@description Contains a list of message positions @total_count Total count of messages found @positions List of message positions
messagePositions total_count:int32 positions:vector<messagePosition> = MessagePositions;
//@description Contains information about found messages sent in a specific day @total_count Total number of found messages sent in the day @message First message sent in the day
messageCalendarDay total_count:int32 message:message = MessageCalendarDay;
//@description Contains information about found messages, splitted by days according to the option "utc_time_offset" @total_count Total number of found messages @days Information about messages sent
messageCalendar total_count:int32 days:vector<messageCalendarDay> = MessageCalendar;
//@description Describes a sponsored message @id Unique sponsored message identifier @sponsor_chat_id Chat identifier
//@link An internal link to be opened when the sponsored message is clicked; may be null. If null, the sponsor chat needs to be opened instead @content Content of the message
@ -923,11 +961,11 @@ chatSourcePublicServiceAnnouncement type:string text:string = ChatSource;
chatPosition list:ChatList order:int64 is_pinned:Bool source:ChatSource = ChatPosition;
//@description Describes a voice chat
//@group_call_id Group call identifier of an active voice chat; 0 if none. Full information about the voice chat can be received through the method getGroupCall
//@has_participants True, if the voice chat has participants
//@default_participant_id Default group call participant identifier to join the voice chat; may be null
voiceChat group_call_id:int32 has_participants:Bool default_participant_id:MessageSender = VoiceChat;
//@description Describes a video chat
//@group_call_id Group call identifier of an active video chat; 0 if none. Full information about the video chat can be received through the method getGroupCall
//@has_participants True, if the video chat has participants
//@default_participant_id Default group call participant identifier to join the video chat; may be null
videoChat group_call_id:int32 has_participants:Bool default_participant_id:MessageSender = VideoChat;
//@description A chat. (Can be a private chat, basic group, supergroup, or secret chat)
@ -952,12 +990,13 @@ voiceChat group_call_id:int32 has_participants:Bool default_participant_id:Messa
//@notification_settings Notification settings for this chat
//@message_ttl_setting Current message Time To Live setting (self-destruct timer) for the chat; 0 if not defined. TTL is counted from the time message or its content is viewed in secret chats and from the send date in other chats
//@theme_name If non-empty, name of a theme, set for the chat
//@action_bar Describes actions which must be possible to do through a chat action bar; may be null
//@voice_chat Contains information about voice chat of the chat
//@action_bar Information about actions which must be possible to do through the chat action bar; may be null
//@video_chat Information about video chat of the chat
//@pending_join_requests Information about pending join requests; may be null
//@reply_markup_message_id Identifier of the message from which reply markup needs to be used; 0 if there is no default custom reply markup in the chat
//@draft_message A draft of a message in the chat; may be null
//@client_data Contains 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 voice_chat:voiceChat reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat;
//@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;
//@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;
@ -1087,7 +1126,7 @@ loginUrlInfoRequestConfirmation url:string domain:string bot_user_id:int53 reque
//@description Contains information about a message thread
//@chat_id Identifier of the chat to which the message thread belongs
//@message_thread_id Message thread identifier, unique within the chat
//@reply_info Contains information about the message thread
//@reply_info Information about the message thread
//@unread_message_count Approximate number of unread messages in the message thread
//@messages The messages from which the thread starts. The messages are returned in a reverse chronological order (i.e., in order of decreasing message_id)
//@draft_message A draft of a message in the message thread; may be null
@ -1373,7 +1412,7 @@ savedCredentials id:string title:string = SavedCredentials;
//@description Applies if a user chooses some previously saved payment credentials. To use their previously saved credentials, the user must have a valid temporary password @saved_credentials_id Identifier of the saved credentials
inputCredentialsSaved saved_credentials_id:string = InputCredentials;
//@description Applies if a user enters new credentials on a payment provider website @data Contains JSON-encoded data with a credential identifier from the payment provider @allow_save True, if the credential identifier can be saved on the server side
//@description Applies if a user enters new credentials on a payment provider website @data JSON-encoded data with the credential identifier from the payment provider @allow_save True, if the credential identifier can be saved on the server side
inputCredentialsNew data:string allow_save:Bool = InputCredentials;
//@description Applies if a user enters new credentials using Apple Pay @data JSON-encoded data with the credential identifier
@ -1396,9 +1435,9 @@ paymentFormTheme background_color:int32 text_color:int32 hint_color:int32 link_c
//@url Payment form URL
//@seller_bot_user_id User identifier of the seller bot
//@payments_provider_user_id User identifier of the payment provider bot
//@payments_provider Contains information about the payment provider, if available, to support it natively without the need for opening the URL; may be null
//@payments_provider Information about the payment provider, if available, to support it natively without the need for opening the URL; may be null
//@saved_order_info Saved server-side order information; may be null
//@saved_credentials Contains information about saved card credentials; may be null
//@saved_credentials Information about saved card credentials; may be null
//@can_save_credentials True, if the user can choose to save credentials
//@need_password True, if the user will be able to save credentials protected by a password they set up
paymentForm id:int64 invoice:invoice url:string seller_bot_user_id:int53 payments_provider_user_id:int53 payments_provider:paymentsProviderStripe saved_order_info:orderInfo saved_credentials:savedCredentials can_save_credentials:Bool need_password:Bool = PaymentForm;
@ -1416,7 +1455,7 @@ paymentResult success:Bool verification_url:string = PaymentResult;
//@date Point in time (Unix timestamp) when the payment was made
//@seller_bot_user_id User identifier of the seller bot
//@payments_provider_user_id User identifier of the payment provider bot
//@invoice Contains information about the invoice
//@invoice Information about the invoice
//@order_info Order information; may be null
//@shipping_option Chosen shipping option; may be null
//@credentials_title Title of the saved credentials chosen by the buyer
@ -1624,7 +1663,7 @@ passportSuitableElement type:PassportElementType is_selfie_required:Bool is_tran
passportRequiredElement suitable_elements:vector<passportSuitableElement> = PassportRequiredElement;
//@description Contains information about a Telegram Passport authorization form that was requested @id Unique identifier of the authorization form
//@required_elements Information about the Telegram Passport elements that must be provided to complete the form
//@required_elements Telegram Passport elements that must be provided to complete the form
//@privacy_policy_url URL for the privacy policy of the service; may be empty
passportAuthorizationForm id:int32 required_elements:vector<passportRequiredElement> privacy_policy_url:string = PassportAuthorizationForm;
@ -1721,6 +1760,9 @@ messageVenue venue:venue = MessageContent;
//@description A message with a user contact @contact The contact description
messageContact contact:contact = MessageContent;
//@description A message with an animated emoji @animated_emoji The animated emoji @emoji The corresponding emoji
messageAnimatedEmoji animated_emoji:animatedEmoji emoji:string = MessageContent;
//@description A dice message. The dice value is randomly generated by the server
//@initial_state The animated stickers with the initial dice animation; may be null if unknown. updateMessageContent will be sent when the sticker became known
//@final_state The animated stickers with the final dice animation; may be null if unknown. updateMessageContent will be sent when the sticker became known
@ -1743,17 +1785,17 @@ messageInvoice title:string description:string photo:photo currency:string total
//@description A message with information about an ended call @is_video True, if the call was a video call @discard_reason Reason why the call was discarded @duration Call duration, in seconds
messageCall is_video:Bool discard_reason:CallDiscardReason duration:int32 = MessageContent;
//@description A new voice chat was scheduled @group_call_id Identifier of the voice chat. The voice chat can be received through the method getGroupCall @start_date Point in time (Unix timestamp) when the group call is supposed to be started by an administrator
messageVoiceChatScheduled group_call_id:int32 start_date:int32 = MessageContent;
//@description A new video chat was scheduled @group_call_id Identifier of the video chat. The video chat can be received through the method getGroupCall @start_date Point in time (Unix timestamp) when the group call is supposed to be started by an administrator
messageVideoChatScheduled group_call_id:int32 start_date:int32 = MessageContent;
//@description A newly created voice chat @group_call_id Identifier of the voice chat. The voice chat can be received through the method getGroupCall
messageVoiceChatStarted group_call_id:int32 = MessageContent;
//@description A newly created video chat @group_call_id Identifier of the video chat. The video chat can be received through the method getGroupCall
messageVideoChatStarted group_call_id:int32 = MessageContent;
//@description A message with information about an ended voice chat @duration Call duration, in seconds
messageVoiceChatEnded duration:int32 = MessageContent;
//@description A message with information about an ended video chat @duration Call duration, in seconds
messageVideoChatEnded duration:int32 = MessageContent;
//@description A message with information about an invite to a voice chat @group_call_id Identifier of the voice chat. The voice chat can be received through the method getGroupCall @user_ids Invited user identifiers
messageInviteVoiceChatParticipants group_call_id:int32 user_ids:vector<int53> = MessageContent;
//@description A message with information about an invite to a video chat @group_call_id Identifier of the video chat. The video chat can be received through the method getGroupCall @user_ids Invited user identifiers
messageInviteVideoChatParticipants group_call_id:int32 user_ids:vector<int53> = MessageContent;
//@description A newly created basic group @title Title of the basic group @member_user_ids User identifiers of members in the basic group
messageBasicGroupChatCreate title:string member_user_ids:vector<int53> = MessageContent;
@ -1776,6 +1818,9 @@ messageChatAddMembers member_user_ids:vector<int53> = MessageContent;
//@description A new member joined the chat by invite link
messageChatJoinByLink = MessageContent;
//@description A new member was accepted to the chat by an administrator
messageChatJoinByRequest = MessageContent;
//@description A chat member was deleted @user_id User identifier of the deleted chat member
messageChatDeleteMember user_id:int53 = MessageContent;
@ -2132,7 +2177,7 @@ stickerSet id:int64 title:string name:string thumbnail:thumbnail thumbnail_outli
//@thumbnail_outline Sticker set thumbnail's outline represented as a list of closed vector paths; may be empty. The coordinate system origin is in the upper-left corner
//@is_installed True, if the sticker set has been installed by the current user @is_archived True, if the sticker set has been archived. A sticker set can't be installed and archived simultaneously
//@is_official True, if the sticker set is official @is_animated True, is the stickers in the set are animated @is_masks True, if the stickers in the set are masks @is_viewed True for already viewed trending sticker sets
//@size Total number of stickers in the set @covers Contains up to the first 5 stickers from the set, depending on the context. If the application needs more stickers the full sticker set needs to be requested
//@size Total number of stickers in the set @covers Up to the first 5 stickers from the set, depending on the context. If the application needs more stickers the full sticker set needs to be requested
stickerSetInfo id:int64 title:string name:string thumbnail:thumbnail thumbnail_outline:vector<closedVectorPath> is_installed:Bool is_archived:Bool is_official:Bool is_animated:Bool is_masks:Bool is_viewed:Bool size:int32 covers:vector<sticker> = StickerSetInfo;
//@description Represents a list of sticker sets @total_count Approximate total number of sticker sets found @sets List of sticker sets
@ -2511,6 +2556,9 @@ chatEventMemberJoined = ChatEventAction;
//@description A new member joined the chat by an invite link @invite_link Invite link used to join the chat
chatEventMemberJoinedByInviteLink invite_link:chatInviteLink = ChatEventAction;
//@description A new member was accepted to the chat by an administrator @approver_user_id User identifier of the chat administrator, approved user join request @invite_link Invite link used to join the chat; may be null
chatEventMemberJoinedByRequest approver_user_id:int53 invite_link:chatInviteLink = ChatEventAction;
//@description A member left the chat
chatEventMemberLeft = ChatEventAction;
@ -2571,20 +2619,20 @@ chatEventInviteLinkRevoked invite_link:chatInviteLink = ChatEventAction;
//@description A revoked chat invite link was deleted @invite_link The invite link
chatEventInviteLinkDeleted invite_link:chatInviteLink = ChatEventAction;
//@description A voice chat was created @group_call_id Identifier of the voice chat. The voice chat can be received through the method getGroupCall
chatEventVoiceChatCreated group_call_id:int32 = ChatEventAction;
//@description A video chat was created @group_call_id Identifier of the video chat. The video chat can be received through the method getGroupCall
chatEventVideoChatCreated group_call_id:int32 = ChatEventAction;
//@description A voice chat was discarded @group_call_id Identifier of the voice chat. The voice chat can be received through the method getGroupCall
chatEventVoiceChatDiscarded group_call_id:int32 = ChatEventAction;
//@description A video chat was discarded @group_call_id Identifier of the video chat. The video chat can be received through the method getGroupCall
chatEventVideoChatDiscarded group_call_id:int32 = ChatEventAction;
//@description A voice chat participant was muted or unmuted @participant_id Identifier of the affected group call participant @is_muted New value of is_muted
chatEventVoiceChatParticipantIsMutedToggled participant_id:MessageSender is_muted:Bool = ChatEventAction;
//@description A video chat participant was muted or unmuted @participant_id Identifier of the affected group call participant @is_muted New value of is_muted
chatEventVideoChatParticipantIsMutedToggled participant_id:MessageSender is_muted:Bool = ChatEventAction;
//@description A voice chat participant volume level was changed @participant_id Identifier of the affected group call participant @volume_level New value of volume_level; 1-20000 in hundreds of percents
chatEventVoiceChatParticipantVolumeLevelChanged participant_id:MessageSender volume_level:int32 = ChatEventAction;
//@description A video chat participant volume level was changed @participant_id Identifier of the affected group call participant @volume_level New value of volume_level; 1-20000 in hundreds of percents
chatEventVideoChatParticipantVolumeLevelChanged participant_id:MessageSender volume_level:int32 = ChatEventAction;
//@description The mute_new_participants setting of a voice chat was toggled @mute_new_participants New value of the mute_new_participants setting
chatEventVoiceChatMuteNewParticipantsToggled mute_new_participants:Bool = ChatEventAction;
//@description The mute_new_participants setting of a video chat was toggled @mute_new_participants New value of the mute_new_participants setting
chatEventVideoChatMuteNewParticipantsToggled mute_new_participants:Bool = ChatEventAction;
//@description Represents a chat event @id Chat event identifier @date Point in time (Unix timestamp) when the event happened @user_id Identifier of the user who performed the action that triggered the event @action Action performed by the user
chatEvent id:int64 date:int32 user_id:int53 action:ChatEventAction = ChatEvent;
@ -2604,8 +2652,8 @@ chatEvents events:vector<chatEvent> = ChatEvents;
//@info_changes True, if changes in chat information need to be returned
//@setting_changes True, if changes in chat settings need to be returned
//@invite_link_changes True, if changes to invite links need to be returned
//@voice_chat_changes True, if voice chat actions need to be returned
chatEventLogFilters message_edits:Bool message_deletions:Bool message_pins:Bool member_joins:Bool member_leaves:Bool member_invites:Bool member_promotions:Bool member_restrictions:Bool info_changes:Bool setting_changes:Bool invite_link_changes:Bool voice_chat_changes:Bool = ChatEventLogFilters;
//@video_chat_changes True, if video chat actions need to be returned
chatEventLogFilters message_edits:Bool message_deletions:Bool message_pins:Bool member_joins:Bool member_leaves:Bool member_invites:Bool member_promotions:Bool member_restrictions:Bool info_changes:Bool setting_changes:Bool invite_link_changes:Bool video_chat_changes:Bool = ChatEventLogFilters;
//@class LanguagePackStringValue @description Represents the value of a string in a language pack
@ -2704,13 +2752,13 @@ backgroundFillFreeformGradient colors:vector<int32> = BackgroundFill;
backgroundTypeWallpaper is_blurred:Bool is_moving:Bool = BackgroundType;
//@description A PNG or TGV (gzipped subset of SVG with MIME type "application/x-tgwallpattern") pattern to be combined with the background fill chosen by the user
//@fill Description of the background fill
//@fill Fill of the background
//@intensity Intensity of the pattern when it is shown above the filled background; 0-100.
//@is_inverted True, if the background fill must be applied only to the pattern itself. All other pixels are black in this case. For dark themes only
//@is_moving True, if the background needs to be slightly moved when device is tilted
backgroundTypePattern fill:BackgroundFill intensity:int32 is_inverted:Bool is_moving:Bool = BackgroundType;
//@description A filled background @fill Description of the background fill
//@description A filled background @fill The background fill
backgroundTypeFill fill:BackgroundFill = BackgroundType;
@ -2905,6 +2953,9 @@ pushMessageContentChatDeleteMember member_name:string is_current_user:Bool is_le
//@description A new member joined the chat by invite link
pushMessageContentChatJoinByLink = PushMessageContent;
//@description A new member was accepted to the chat by an administrator
pushMessageContentChatJoinByRequest = PushMessageContent;
//@description A forwarded messages @total_count Number of forwarded messages
pushMessageContentMessageForwards total_count:int32 = PushMessageContent;
@ -3194,10 +3245,13 @@ internalLinkTypeThemeSettings = InternalLinkType;
//@description The link is an unknown tg: link. Call getDeepLinkInfo to process the link @link Link to be passed to getDeepLinkInfo
internalLinkTypeUnknownDeepLink link:string = InternalLinkType;
//@description The link is a link to a voice chat. Call searchPublicChat with the given chat username, and then joinGoupCall with the given invite hash to process the link
//@chat_username Username of the chat with the voice chat @invite_hash If non-empty, invite hash to be used to join the voice chat without being muted by administrators
//@is_live_stream True, if the voice chat is expected to be a live stream in a channel or a broadcast group
internalLinkTypeVoiceChat chat_username:string invite_hash:string is_live_stream:Bool = InternalLinkType;
//@description The link is a link to an unsupported proxy. An alert can be shown to the user
internalLinkTypeUnsupportedProxy = InternalLinkType;
//@description The link is a link to a video chat. Call searchPublicChat with the given chat username, and then joinGoupCall with the given invite hash to process the link
//@chat_username Username of the chat with the video chat @invite_hash If non-empty, invite hash to be used to join the video chat without being muted by administrators
//@is_live_stream True, if the video chat is expected to be a live stream in a channel or a broadcast group
internalLinkTypeVideoChat chat_username:string invite_hash:string is_live_stream:Bool = InternalLinkType;
//@description Contains an HTTPS link to a message in a supergroup or channel @link Message link @is_public True, if the link will work for non-members of the chat
@ -3621,11 +3675,11 @@ updateNewMessage message:message = Update;
//@chat_id The chat identifier of the sent message @message_id A temporary message identifier
updateMessageSendAcknowledged chat_id:int53 message_id:int53 = Update;
//@description A message has been successfully sent @message Information about the sent message. Usually only the message identifier, date, and content are changed, but almost all other fields can also change @old_message_id The previous temporary message identifier
//@description A message has been successfully sent @message The sent message. Usually only the message identifier, date, and content are changed, but almost all other fields can also change @old_message_id The previous temporary message identifier
updateMessageSendSucceeded message:message old_message_id:int53 = Update;
//@description A message failed to send. Be aware that some messages being sent can be irrecoverably deleted, in which case updateDeleteMessages will be received instead of this update
//@message Contains information about the message which failed to send @old_message_id The previous temporary message identifier @error_code An error code @error_message Error message
//@message The failed to send message @old_message_id The previous temporary message identifier @error_code An error code @error_message Error message
updateMessageSendFailed message:message old_message_id:int53 error_code:int32 error_message:string = Update;
//@description The message content has changed @chat_id Chat identifier @message_id Message identifier @new_content New message content
@ -3677,8 +3731,8 @@ updateChatIsBlocked chat_id:int53 is_blocked:Bool = Update;
//@description A chat's has_scheduled_messages field has changed @chat_id Chat identifier @has_scheduled_messages New value of has_scheduled_messages
updateChatHasScheduledMessages chat_id:int53 has_scheduled_messages:Bool = Update;
//@description A chat voice chat state has changed @chat_id Chat identifier @voice_chat New value of voice_chat
updateChatVoiceChat chat_id:int53 voice_chat:voiceChat = Update;
//@description A chat video chat state has changed @chat_id Chat identifier @video_chat New value of video_chat
updateChatVideoChat chat_id:int53 video_chat:videoChat = Update;
//@description The value of the default disable_notification parameter, used when a message is sent to the chat, was changed @chat_id Chat identifier @default_disable_notification The new default_disable_notification value
updateChatDefaultDisableNotification chat_id:int53 default_disable_notification:Bool = Update;
@ -3707,6 +3761,9 @@ updateChatActionBar chat_id:int53 action_bar:ChatActionBar = Update;
//@description The chat theme was changed @chat_id Chat identifier @theme_name The new name of the chat theme; may be empty if theme was reset to default
updateChatTheme chat_id:int53 theme_name:string = Update;
//@description The chat pending join requests were changed @chat_id Chat identifier @pending_join_requests The new data about pending join requests; may be null
updateChatPendingJoinRequests chat_id:int53 pending_join_requests:chatJoinRequestsInfo = Update;
//@description The default chat reply markup was changed. Can occur because new messages with reply markup were received or because an old reply markup was hidden by the user
//@chat_id Chat identifier @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
updateChatReplyMarkup chat_id:int53 reply_markup_message_id:int53 = Update;
@ -3874,7 +3931,7 @@ updateAnimationSearchParameters provider:string emojis:vector<string> = Update;
updateSuggestedActions added_actions:vector<SuggestedAction> removed_actions:vector<SuggestedAction> = Update;
//@description A new incoming inline query; for bots only @id Unique query identifier @sender_user_id Identifier of the user who sent the query @user_location User location; may be null
//@chat_type Contains information about the type of the chat, from which the query originated; may be null if unknown @query Text of the query @offset Offset of the first entry to return
//@chat_type The type of the chat, from which the query originated; may be null if unknown @query Text of the query @offset Offset of the first entry to return
updateNewInlineQuery id:int64 sender_user_id:int53 user_location:location chat_type:ChatType query:string offset:string = Update;
//@description The user has chosen a result of an inline query; for bots only @sender_user_id Identifier of the user who sent the query @user_location User location; may be null
@ -3914,6 +3971,9 @@ updatePollAnswer poll_id:int64 user_id:int53 option_ids:vector<int32> = Update;
//@old_chat_member Previous chat member @new_chat_member New chat member
updateChatMember chat_id:int53 actor_user_id:int53 date:int32 invite_link:chatInviteLink old_chat_member:chatMember new_chat_member:chatMember = Update;
//@description A user sent a join request to a chat; for bots only @chat_id Chat identifier @request Join request @invite_link The invite link, which was used to send join request; may be null
updateNewChatJoinRequest chat_id:int53 request:chatJoinRequest invite_link:chatInviteLink = Update;
//@description Contains a list of updates @updates List of updates
updates updates:vector<Update> = Updates;
@ -4267,6 +4327,20 @@ getActiveLiveLocationMessages = Messages;
//@description Returns the last message sent in a chat no later than the specified date @chat_id Chat identifier @date Point in time (Unix timestamp) relative to which to search for messages
getChatMessageByDate chat_id:int53 date:int32 = Message;
//@description Returns sparse positions of messages of the specified type in the chat to be used for shared media scroll implementation. Returns the results in reverse chronological order (i.e., in order of decreasing message_id).
//-Cannot be used in secret chats or with searchMessagesFilterFailedToSend filter without an enabled message database
//@chat_id Identifier of the chat in which to return information about message positions
//@filter Filter for message content. Filters searchMessagesFilterEmpty, searchMessagesFilterCall, searchMessagesFilterMissedCall, searchMessagesFilterMention and searchMessagesFilterUnreadMention are unsupported in this function
//@from_message_id The message identifier from which to return information about message positions
//@limit The expected number of message positions to be returned; 50-2000. A smaller number of positions can be returned, if there are not enough appropriate messages
getChatSparseMessagePositions chat_id:int53 filter:SearchMessagesFilter from_message_id:int53 limit:int32 = MessagePositions;
//@description Returns information about the next messages of the specified type in the chat splitted by days. Returns the results in reverse chronological order. Can return partial result for the last returned day. Behavior of this method depends on the value of the option "utc_time_offset"
//@chat_id Identifier of the chat in which to return information about messages
//@filter Filter for message content. Filters searchMessagesFilterEmpty, searchMessagesFilterCall, searchMessagesFilterMissedCall, searchMessagesFilterMention and searchMessagesFilterUnreadMention are unsupported in this function
//@from_message_id The message identifier from which to return information about messages; use 0 to get results from the last message
getChatMessageCalendar chat_id:int53 filter:SearchMessagesFilter from_message_id:int53 = MessageCalendar;
//@description Returns approximate number of messages of the specified type in the chat @chat_id Identifier of the chat in which to count messages @filter Filter for message content; searchMessagesFilterEmpty is unsupported in this function @return_local If true, returns count that is available locally without sending network requests, returning -1 if the number of messages is unknown
getChatMessageCount chat_id:int53 filter:SearchMessagesFilter return_local:Bool = Count;
@ -4375,6 +4449,10 @@ 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
deleteChatMessagesFromUser chat_id:int53 user_id:int53 = 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
//@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
deleteChatMessagesByDate chat_id:int53 min_date:int32 max_date:int32 revoke:Bool = Ok;
//@description Edits the text of a message (or a text of a game message). Returns the edited message after the edit is completed on the server side
//@chat_id The chat the message belongs to
@ -4876,16 +4954,20 @@ replacePrimaryChatInviteLink chat_id:int53 = ChatInviteLink;
//@description Creates a new invite link for a chat. Available for basic groups, supergroups, and channels. Requires administrator privileges and can_invite_users right in the chat
//@chat_id Chat identifier
//@name Invite link name; 0-32 characters
//@expire_date Point in time (Unix timestamp) when the link will expire; pass 0 if never
//@member_limit The maximum number of chat members that can join the chat by the link simultaneously; 0-99999; pass 0 if not limited
createChatInviteLink chat_id:int53 expire_date:int32 member_limit:int32 = ChatInviteLink;
//@creates_join_request True, if the link only creates join request. If true, member_limit must not be specified
createChatInviteLink chat_id:int53 name:string expire_date:int32 member_limit:int32 creates_join_request:Bool = ChatInviteLink;
//@description Edits a non-primary invite link for a chat. Available for basic groups, supergroups, and channels. Requires administrator privileges and can_invite_users right in the chat for own links and owner privileges for other links
//@chat_id Chat identifier
//@invite_link Invite link to be edited
//@name Invite link name; 0-32 characters
//@expire_date Point in time (Unix timestamp) when the link will expire; pass 0 if never
//@member_limit The maximum number of chat members that can join the chat by the link simultaneously; 0-99999; pass 0 if not limited
editChatInviteLink chat_id:int53 invite_link:string expire_date:int32 member_limit:int32 = ChatInviteLink;
//@creates_join_request True, if the link only creates join request. If true, member_limit must not be specified
editChatInviteLink chat_id:int53 invite_link:string name:string expire_date:int32 member_limit:int32 creates_join_request:Bool = ChatInviteLink;
//@description Returns information about an invite link. Requires administrator privileges and can_invite_users right in the chat to get own links and owner privileges to get other links
//@chat_id Chat identifier
@ -4928,11 +5010,25 @@ checkChatInviteLink invite_link:string = ChatInviteLinkInfo;
//@description Uses an invite link to add the current user to the chat if possible @invite_link Invite link to use
joinChatByInviteLink invite_link:string = Chat;
//@description Returns pending join requests in a chat
//@chat_id Chat identifier
//@invite_link Invite link for which to return join requests. If empty, all join requests will be returned. Requires administrator privileges and can_invite_users right in the chat for own links and owner privileges for other links
//@query A query to search for in the first names, last names and usernames of the users to return
//@offset_request A chat join request from which to return next requests; pass null to get results from the beginning
//@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;
//@description Creates a new call @user_id Identifier of the user to be called @protocol Description of the call protocols supported by the application @is_video True, if a video call needs to be created
//@description Approves pending join request in a chat @chat_id Chat identifier @user_id Identifier of the user, which request will be approved
approveChatJoinRequest chat_id:int53 user_id:int53 = Ok;
//@description Declines pending join request in a chat @chat_id Chat identifier @user_id Identifier of the user, which request will be declined
declineChatJoinRequest chat_id:int53 user_id:int53 = 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
createCall user_id:int53 protocol:callProtocol is_video:Bool = CallId;
//@description Accepts an incoming call @call_id Call identifier @protocol Description of the call protocols supported by the application
//@description Accepts an incoming call @call_id Call identifier @protocol The call protocols supported by the application
acceptCall call_id:int32 protocol:callProtocol = Ok;
//@description Sends call signaling data @call_id Call identifier @data The data
@ -4948,17 +5044,17 @@ sendCallRating call_id:int32 rating:int32 comment:string problems:vector<CallPro
sendCallDebugInformation call_id:int32 debug_information:string = Ok;
//@description Returns list of participant identifiers, which can be used to join voice chats in a chat @chat_id Chat identifier
getVoiceChatAvailableParticipants chat_id:int53 = MessageSenders;
//@description Returns list of participant identifiers, which can be used to join video chats in a chat @chat_id Chat identifier
getVideoChatAvailableParticipants chat_id:int53 = MessageSenders;
//@description Changes default participant identifier, which can be used to join voice chats in a chat @chat_id Chat identifier @default_participant_id Default group call participant identifier to join the voice chats
setVoiceChatDefaultParticipant chat_id:int53 default_participant_id:MessageSender = Ok;
//@description Changes default participant identifier, which can be used to join video chats in a chat @chat_id Chat identifier @default_participant_id Default group call participant identifier to join the video chats
setVideoChatDefaultParticipant chat_id:int53 default_participant_id:MessageSender = Ok;
//@description Creates a voice chat (a group call bound to a chat). Available only for basic groups, supergroups and channels; requires can_manage_voice_chats rights
//@chat_id Chat identifier, in which the voice chat will be created
//@description Creates a video chat (a group call bound to a chat). Available only for basic groups, supergroups and channels; requires can_manage_video_chats rights
//@chat_id Chat identifier, in which the video chat will be created
//@title Group call title; if empty, chat title will be used
//@start_date Point in time (Unix timestamp) when the group call is supposed to be started by an administrator; 0 to start the voice chat immediately. The date must be at least 10 seconds and at most 8 days in the future
createVoiceChat chat_id:int53 title:string start_date:int32 = GroupCallId;
//@start_date Point in time (Unix timestamp) when the group call is supposed to be started by an administrator; 0 to start the video chat immediately. The date must be at least 10 seconds and at most 8 days in the future
createVideoChat chat_id:int53 title:string start_date:int32 = GroupCallId;
//@description Returns information about a group call @group_call_id Group call identifier
getGroupCall group_call_id:int32 = GroupCall;
@ -4972,7 +5068,7 @@ toggleGroupCallEnabledStartNotification group_call_id:int32 enabled_start_notifi
//@description Joins an active group call. Returns join response payload for tgcalls
//@group_call_id Group call identifier
//@participant_id Identifier of a group call participant, which will be used to join the call; pass null to join as self; voice chats only
//@participant_id Identifier of a group call participant, which will be used to join the call; pass null to join as self; video chats only
//@audio_source_id Caller audio channel synchronization source identifier; received from tgcalls
//@payload Group call join payload; received from tgcalls
//@is_muted True, if the user's microphone is muted
@ -5002,11 +5098,11 @@ toggleGroupCallMuteNewParticipants group_call_id:int32 mute_new_participants:Boo
//@description Revokes invite link for a group call. Requires groupCall.can_be_managed group call flag @group_call_id Group call identifier
revokeGroupCallInviteLink group_call_id:int32 = Ok;
//@description Invites users to an active group call. Sends a service message of type messageInviteToGroupCall for voice chats
//@description Invites users to an active group call. Sends a service message of type messageInviteToGroupCall for video chats
//@group_call_id Group call identifier @user_ids User identifiers. At most 10 users can be invited simultaneously
inviteGroupCallParticipants group_call_id:int32 user_ids:vector<int53> = Ok;
//@description Returns invite link to a voice chat in a public chat
//@description Returns invite link to a video chat in a public chat
//@group_call_id Group call identifier
//@can_self_unmute Pass true if the invite link needs to contain an invite hash, passing which to joinGroupCall would allow the invited user to unmute themselves. Requires groupCall.can_be_managed group call flag
getGroupCallInviteLink group_call_id:int32 can_self_unmute:Bool = HttpUrl;
@ -5180,6 +5276,9 @@ getStickerEmojis sticker:InputFile = Emojis;
//@description Searches for emojis by keywords. Supported only if the file database is enabled @text Text to search for @exact_match True, if only emojis, which exactly match text needs to be returned @input_language_codes List of possible IETF language tags of the user's input language; may be empty if unknown
searchEmojis text:string exact_match:Bool input_language_codes:vector<string> = Emojis;
//@description Returns an animated emoji corresponding to a given emoji. Returns a 404 error if the emoji has no animated emoji @emoji The emoji
getAnimatedEmoji emoji:string = AnimatedEmoji;
//@description Returns an HTTP URL which can be used to automatically log in to the translation platform and suggest new emoji replacements. The URL will be valid for 30 seconds after generation @language_code Language code for which the emoji replacements will be suggested
getEmojiSuggestionsUrl language_code:string = HttpUrl;

View File

@ -118,8 +118,8 @@ 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;
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#4dbdc099 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 = ChatFull;
channelFull#e9b27a17 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 = 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;
chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant;
chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant;
@ -178,6 +178,7 @@ messageActionInviteToGroupCall#502f92f7 call:InputGroupCall users:Vector<long> =
messageActionSetMessagesTTL#aa1afbfd period:int = MessageAction;
messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction;
messageActionSetChatTheme#aa786345 emoticon:string = MessageAction;
messageActionChatJoinedByRequest#ebbca3cb = MessageAction;
dialog#2c171f72 flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int = Dialog;
dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog;
@ -368,6 +369,8 @@ updateChannelParticipant#985d3abb flags:# channel_id:long date:int actor_id:long
updateBotStopped#c4870a49 user_id:long date:int stopped:Bool qts:int = Update;
updateGroupCallConnection#b783982 flags:# presentation:flags.0?true params:DataJSON = Update;
updateBotCommands#4d712f2e peer:Peer bot_id:long commands:Vector<BotCommand> = Update;
updatePendingJoinRequests#7063c3db peer:Peer requests_pending:int recent_requesters:Vector<long> = Update;
updateBotChatInviteRequester#11dfa986 peer:Peer date:int user_id:long about:string invite:ExportedChatInvite qts:int = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@ -539,10 +542,10 @@ auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery;
receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage;
chatInviteExported#b18105e8 flags:# revoked:flags.0?true permanent:flags.5?true link:string admin_id:long date:int start_date:flags.4?int expire_date:flags.1?int usage_limit:flags.2?int usage:flags.3?int = ExportedChatInvite;
chatInviteExported#ab4a819 flags:# revoked:flags.0?true permanent:flags.5?true request_needed:flags.6?true link:string admin_id:long date:int start_date:flags.4?int expire_date:flags.1?int usage_limit:flags.2?int usage:flags.3?int requested:flags.7?int title:flags.8?string = ExportedChatInvite;
chatInviteAlready#5a686d7c chat:Chat = ChatInvite;
chatInvite#dfc2f58e flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:Photo participants_count:int participants:flags.4?Vector<User> = ChatInvite;
chatInvite#300c44c1 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true request_needed:flags.6?true title:string about:flags.5?string photo:Photo participants_count:int participants:flags.4?Vector<User> = ChatInvite;
chatInvitePeek#61695cb0 chat:Chat expires:int = ChatInvite;
inputStickerSetEmpty#ffb62b95 = InputStickerSet;
@ -615,7 +618,7 @@ channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter;
channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector<MessageRange> = ChannelMessagesFilter;
channelParticipant#c00c07c0 user_id:long date:int = ChannelParticipant;
channelParticipantSelf#28a8bc67 user_id:long inviter_id:long date:int = ChannelParticipant;
channelParticipantSelf#35a8bfa7 flags:# via_invite: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;
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;
@ -898,6 +901,7 @@ channelAdminLogEventActionExportedInviteRevoke#410a134e invite:ExportedChatInvit
channelAdminLogEventActionExportedInviteEdit#e90ebb59 prev_invite:ExportedChatInvite new_invite:ExportedChatInvite = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantVolume#3e7f6847 participant:GroupCallParticipant = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeHistoryTTL#6e941a38 prev_value:int new_value:int = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantJoinByRequest#afb6144a invite:ExportedChatInvite approved_by:long = ChannelAdminLogEventAction;
channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
@ -1112,7 +1116,7 @@ restrictionReason#d072acb4 platform:string reason:string text:string = Restricti
inputTheme#3c5693e9 id:long access_hash:long = InputTheme;
inputThemeSlug#f5890df1 slug:string = InputTheme;
theme#e802b8dc flags:# creator:flags.0?true default:flags.1?true for_chat:flags.5?true id:long access_hash:long slug:string title:string document:flags.2?Document settings:flags.3?ThemeSettings installs_count:flags.4?int = Theme;
theme#a00e67d6 flags:# creator:flags.0?true default:flags.1?true for_chat:flags.5?true id:long access_hash:long slug:string title:string document:flags.2?Document settings:flags.3?Vector<ThemeSettings> emoticon:flags.6?string installs_count:flags.4?int = Theme;
account.themesNotModified#f41eb622 = account.Themes;
account.themes#9a3d8c6d hash:long themes:Vector<Theme> = account.Themes;
@ -1224,7 +1228,7 @@ messages.historyImportParsed#5e0fb7b9 flags:# pm:flags.0?true group:flags.1?true
messages.affectedFoundMessages#ef8d3e6c pts:int pts_count:int offset:int messages:Vector<int> = messages.AffectedFoundMessages;
chatInviteImporter#b5cd5f4 user_id:long date:int = ChatInviteImporter;
chatInviteImporter#8c5adfd9 flags:# requested:flags.0?true user_id:long date:int about:flags.2?string approved_by:flags.1?long = ChatInviteImporter;
messages.exportedChatInvites#bdc62dcc count:int invites:Vector<ExportedChatInvite> users:Vector<User> = messages.ExportedChatInvites;
@ -1261,15 +1265,18 @@ account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordR
account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult;
account.resetPasswordOk#e926d63e = account.ResetPasswordResult;
chatTheme#ed0b5c33 emoticon:string theme:Theme dark_theme:Theme = ChatTheme;
account.chatThemesNotModified#e011e1c4 = account.ChatThemes;
account.chatThemes#fe4cbebd hash:int themes:Vector<ChatTheme> = account.ChatThemes;
sponsoredMessage#2a3c381f flags:# random_id:bytes from_id:Peer start_param:flags.0?string message:string entities:flags.1?Vector<MessageEntity> = SponsoredMessage;
sponsoredMessage#d151e19a flags:# random_id:bytes from_id:Peer channel_post:flags.2?int start_param:flags.0?string message:string entities:flags.1?Vector<MessageEntity> = SponsoredMessage;
messages.sponsoredMessages#65a4c7d5 messages:Vector<SponsoredMessage> chats:Vector<Chat> users:Vector<User> = messages.SponsoredMessages;
searchResultsCalendarPeriod#c9b0539f date:int min_msg_id:int max_msg_id:int count:int = SearchResultsCalendarPeriod;
messages.searchResultsCalendar#147ee23c flags:# inexact:flags.0?true count:int min_date:int min_msg_id:int offset_id_offset:flags.1?int periods:Vector<SearchResultsCalendarPeriod> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.SearchResultsCalendar;
searchResultPosition#7f648b67 msg_id:int date:int offset:int = SearchResultsPosition;
messages.searchResultsPositions#53b22baf count:int positions:Vector<SearchResultsPosition> = messages.SearchResultsPositions;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@ -1356,10 +1363,10 @@ account.resetWallPapers#bb3b9804 = Bool;
account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings;
account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool;
account.uploadTheme#1c3db333 flags:# file:InputFile thumb:flags.0?InputFile file_name:string mime_type:string = Document;
account.createTheme#8432c21f flags:# slug:string title:string document:flags.2?InputDocument settings:flags.3?InputThemeSettings = Theme;
account.updateTheme#5cb367d5 flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument settings:flags.3?InputThemeSettings = Theme;
account.createTheme#652e4400 flags:# slug:string title:string document:flags.2?InputDocument settings:flags.3?Vector<InputThemeSettings> = Theme;
account.updateTheme#2bf40ccc flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument settings:flags.3?Vector<InputThemeSettings> = Theme;
account.saveTheme#f257106c theme:InputTheme unsave:Bool = Bool;
account.installTheme#7ae43737 flags:# dark:flags.0?true format:flags.1?string theme:flags.1?InputTheme = Bool;
account.installTheme#c727bb3b flags:# dark:flags.0?true theme:flags.1?InputTheme format:flags.2?string base_theme:flags.3?BaseTheme = Bool;
account.getTheme#8d9d742b format:string theme:InputTheme document_id:long = Theme;
account.getThemes#7206e458 format:string hash:long = account.Themes;
account.setContentSettings#b574b16b flags:# sensitive_enabled:flags.0?true = Bool;
@ -1370,7 +1377,7 @@ account.setGlobalPrivacySettings#1edaaac2 settings:GlobalPrivacySettings = Globa
account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:ReportReason message:string = Bool;
account.resetPassword#9308ce1b = account.ResetPasswordResult;
account.declinePasswordReset#4c9409f6 = Bool;
account.getChatThemes#d6d71d7b hash:int = account.ChatThemes;
account.getChatThemes#d638de89 hash:long = account.Themes;
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
@ -1402,7 +1409,7 @@ messages.getDialogs#a0f4cb4f flags:# exclude_pinned:flags.0?true folder_id:flags
messages.getHistory#4423e6c5 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages;
messages.search#a0fda762 flags:# peer:InputPeer q:string from_id:flags.0?InputPeer top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages;
messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int = messages.AffectedHistory;
messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory;
messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool;
@ -1434,7 +1441,7 @@ messages.readMessageContents#36a73f77 id:Vector<int> = messages.AffectedMessages
messages.getStickers#d5a5d3a1 emoticon:string hash:long = messages.Stickers;
messages.getAllStickers#b8a0a1a8 hash:long = messages.AllStickers;
messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector<MessageEntity> = MessageMedia;
messages.exportChatInvite#14b9bcd7 flags:# legacy_revoke_permanent:flags.2?true peer:InputPeer expire_date:flags.0?int usage_limit:flags.1?int = 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.importChatInvite#6c50051c hash:string = Updates;
messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet;
@ -1531,15 +1538,18 @@ messages.uploadImportedMedia#2a862092 peer:InputPeer import_id:long file_name:st
messages.startHistoryImport#b43df344 peer:InputPeer import_id:long = Bool;
messages.getExportedChatInvites#a2b5a3f6 flags:# revoked:flags.3?true peer:InputPeer admin_id:InputUser offset_date:flags.2?int offset_link:flags.2?string limit:int = messages.ExportedChatInvites;
messages.getExportedChatInvite#73746f5c peer:InputPeer link:string = messages.ExportedChatInvite;
messages.editExportedChatInvite#2e4ffbe flags:# revoked:flags.2?true peer:InputPeer link:string expire_date:flags.0?int usage_limit:flags.1?int = messages.ExportedChatInvite;
messages.editExportedChatInvite#bdca2f75 flags:# revoked:flags.2?true peer:InputPeer link:string expire_date:flags.0?int usage_limit:flags.1?int request_needed:flags.3?Bool title:flags.4?string = messages.ExportedChatInvite;
messages.deleteRevokedExportedChatInvites#56987bd5 peer:InputPeer admin_id:InputUser = Bool;
messages.deleteExportedChatInvite#d464a42b peer:InputPeer link:string = Bool;
messages.getAdminsWithInvites#3920e6ef peer:InputPeer = messages.ChatAdminsWithInvites;
messages.getChatInviteImporters#26fb7289 peer:InputPeer link:string offset_date:int offset_user:InputUser limit:int = messages.ChatInviteImporters;
messages.getChatInviteImporters#df04dd4e flags:# requested:flags.0?true peer:InputPeer link:flags.1?string q:flags.2?string offset_date:int offset_user:InputUser limit:int = messages.ChatInviteImporters;
messages.setHistoryTTL#b80e5fe4 peer:InputPeer period:int = Updates;
messages.checkHistoryImportPeer#5dc60f03 peer:InputPeer = messages.CheckedHistoryImportPeer;
messages.setChatTheme#e63be13f peer:InputPeer emoticon:string = Updates;
messages.getMessageReadParticipants#2c6f97b7 peer:InputPeer msg_id:int = Vector<long>;
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.hideChatJoinRequest#7fe7e815 flags:# approved:flags.0?true peer:InputPeer user_id:InputUser = Updates;
updates.getState#edd4882a = updates.State;
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;

View File

@ -276,7 +276,6 @@ class TlWriterCCommon final : public tl::TL_writer {
"#include \"td/utils/logging.h\"\n"
"#include \"td/utils/misc.h\"\n"
"#include \"td/utils/Slice.h\"\n"
"#include \"td/utils/tl_storers.h\"\n"
"\n";
}
std::string gen_output_end() const final {

View File

@ -25,7 +25,8 @@ std::string TD_TL_writer_cpp::gen_output_begin() const {
"#include \"td/utils/logging.h\"\n"
"#include \"td/utils/SliceBuilder.h\"\n"
"#include \"td/utils/tl_parsers.h\"\n"
"#include \"td/utils/tl_storers.h\"\n\n"
"#include \"td/utils/tl_storers.h\"\n"
"#include \"td/utils/TlStorerToString.h\"\n\n"
"namespace td {\n"
"namespace " +
tl_name +
@ -33,7 +34,7 @@ std::string TD_TL_writer_cpp::gen_output_begin() const {
"std::string to_string(const BaseObject &value) {\n"
" TlStorerToString storer;\n"
" value.store(storer, \"\");\n"
" return storer.move_as_str();\n"
" return storer.move_as_string();\n"
"}\n";
}
@ -283,7 +284,7 @@ std::string TD_TL_writer_cpp::gen_var_type_fetch(const tl::arg &a) const {
}
std::string TD_TL_writer_cpp::get_pretty_field_name(std::string field_name) const {
if (!field_name.empty() && field_name.back() == ']') {
if (!field_name.empty() && field_name[0] == '_') {
return "";
}
auto equals_pos = field_name.find('=');
@ -305,16 +306,10 @@ std::string TD_TL_writer_cpp::get_pretty_class_name(std::string class_name) cons
std::string TD_TL_writer_cpp::gen_vector_store(const std::string &field_name, const tl::tl_tree_type *t,
const std::vector<tl::var_description> &vars, int storer_type) const {
std::string num = field_name.back() == ']' ? "2" : "";
return "{ const array<" + gen_type_name(t) + "> &v" + num + " = " + field_name +
"; const std::uint32_t multiplicity" + num + " = static_cast<std::uint32_t>(v" + num +
".size()); const auto vector_name" + num + " = \"" + get_pretty_class_name("vector") +
"[\" + td::to_string(multiplicity" + num + ")+ \"]\"; s.store_class_begin(\"" +
get_pretty_field_name(field_name) + "\", vector_name" + num +
".c_str()); "
"for (std::uint32_t i" +
num + " = 0; i" + num + " < multiplicity" + num + "; i" + num + "++) { " +
gen_type_store("v" + num + "[i" + num + "]", t, vars, storer_type) + " } s.store_class_end(); }";
std::string num = !field_name.empty() && field_name[0] == '_' ? "2" : "";
return "{ s.store_vector_begin(\"" + get_pretty_field_name(field_name) + "\", " + field_name +
".size()); for (const auto &_value" + num + " : " + field_name + ") { " +
gen_type_store("_value" + num, t, vars, storer_type) + " } s.store_class_end(); }";
}
std::string TD_TL_writer_cpp::gen_store_class_name(const tl::tl_tree_type *tree_type) const {
@ -329,7 +324,8 @@ std::string TD_TL_writer_cpp::gen_store_class_name(const tl::tl_tree_type *tree_
return "TlStoreBool";
}
if (name == "True") {
return "TlStoreTrue";
assert(false);
return "";
}
if (name == "String" || name == "Bytes") {
return "TlStoreString";
@ -404,8 +400,8 @@ std::string TD_TL_writer_cpp::gen_type_store(const std::string &field_name, cons
return gen_vector_store(field_name, child, vars, storer_type);
} else {
assert(tree_type->children.empty());
return "if (" + field_name + " == nullptr) { s.store_field(\"" + get_pretty_field_name(field_name) +
"\", \"null\"); } else { " + field_name + "->store(s, \"" + get_pretty_field_name(field_name) + "\"); }";
return "s.store_object_field(\"" + get_pretty_field_name(field_name) + "\", static_cast<const BaseObject *>(" +
field_name + ".get()));";
}
}
@ -443,6 +439,13 @@ std::string TD_TL_writer_cpp::gen_field_store(const tl::arg &a, std::vector<tl::
return "";
}
if (a.exist_var_num >= 0 && a.var_num < 0 && a.type->get_type() == tl::NODE_TYPE_TYPE) {
const tl::tl_tree_type *tree_type = static_cast<tl::tl_tree_type *>(a.type);
if (tree_type->type->name == "True") {
return "";
}
}
if (a.exist_var_num >= 0) {
assert(a.exist_var_num < static_cast<int>(vars.size()));
assert(vars[a.exist_var_num].is_stored);

View File

@ -164,13 +164,34 @@ std::string TD_TL_writer_h::gen_function_vars(const tl::tl_combinator *t,
return res;
}
std::string TD_TL_writer_h::gen_flags_definitions(const tl::tl_combinator *t) const {
bool TD_TL_writer_h::need_arg_mask(const tl::arg &a, bool can_be_stored) const {
if (a.exist_var_num == -1) {
return false;
}
if (can_be_stored) {
return true;
}
if (a.type->get_type() != tl::NODE_TYPE_TYPE) {
return true;
}
const tl::tl_tree_type *tree_type = static_cast<tl::tl_tree_type *>(a.type);
const std::string &name = tree_type->type->name;
if (!is_built_in_simple_type(name) || name == "True") {
return false;
}
return true;
}
std::string TD_TL_writer_h::gen_flags_definitions(const tl::tl_combinator *t, bool can_be_stored) const {
std::vector<std::pair<std::string, std::int32_t>> flags;
for (std::size_t i = 0; i < t->args.size(); i++) {
const tl::arg &a = t->args[i];
if (a.exist_var_num != -1) {
if (need_arg_mask(a, can_be_stored)) {
auto name = a.name;
for (auto &c : name) {
c = to_upper(c);
@ -180,7 +201,7 @@ std::string TD_TL_writer_h::gen_flags_definitions(const tl::tl_combinator *t) co
}
std::string res;
if (!flags.empty()) {
res += " enum Flags : std::int32_t {";
res += " enum Flags : std::int32_t { ";
bool first = true;
for (auto &p : flags) {
if (first) {
@ -190,7 +211,7 @@ std::string TD_TL_writer_h::gen_flags_definitions(const tl::tl_combinator *t) co
}
res += p.first + "_MASK = " + int_to_string(1 << p.second);
}
res += "};\n";
res += " };\n";
}
return res;
}

View File

@ -20,6 +20,8 @@ class TD_TL_writer_h : public TD_TL_writer {
static std::string forward_declaration(std::string type);
bool need_arg_mask(const tl::arg &a, bool can_be_stored) const;
public:
TD_TL_writer_h(const std::string &tl_name, const std::string &string_type, const std::string &bytes_type,
const std::vector<std::string> &ext_include)
@ -40,7 +42,7 @@ class TD_TL_writer_h : public TD_TL_writer {
std::string gen_field_definition(const std::string &class_name, const std::string &type_name,
const std::string &field_name) const override;
std::string gen_flags_definitions(const tl::tl_combinator *t) const override;
std::string gen_flags_definitions(const tl::tl_combinator *t, bool can_be_stored) const override;
std::string gen_vars(const tl::tl_combinator *t, const tl::tl_tree_type *result_type,
std::vector<tl::var_description> &vars) const override;
std::string gen_function_vars(const tl::tl_combinator *t, std::vector<tl::var_description> &vars) const override;

View File

@ -322,8 +322,8 @@ std::string TD_TL_writer_jni_cpp::gen_type_store(const std::string &field_name,
res = gen_vector_store(field_name, child, vars, storer_type);
} else {
if (storer_type == 1) {
res = "if (" + field_name + " == nullptr) { s.store_field(\"" + get_pretty_field_name(field_name) +
"\", \"null\"); } else { " + field_name + "->store(s, \"" + get_pretty_field_name(field_name) + "\"); }";
res = "s.store_object_field(\"" + get_pretty_field_name(field_name) + "\", static_cast<const BaseObject *>(" +
field_name + ".get()));";
} else {
res = "if (" + field_name + " != nullptr) { jobject next; " + field_name +
"->store(env, next); if (next) { env->SetObjectField(s, " + field_name +

View File

@ -10,8 +10,6 @@
#include "td/telegram/files/FileManager.h"
#include "td/telegram/secret_api.h"
#include "td/telegram/Td.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"

View File

@ -6,12 +6,11 @@
//
#pragma once
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/files/FileId.h"
#include "td/telegram/Photo.h"
#include "td/telegram/SecretInputMedia.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/buffer.h"
#include "td/utils/common.h"

View File

@ -6,9 +6,6 @@
//
#include "td/telegram/AuthManager.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/AuthManager.hpp"
#include "td/telegram/ConfigManager.h"
#include "td/telegram/ConfigShared.h"
@ -571,8 +568,7 @@ void AuthManager::on_get_password_result(NetQueryPtr &result) {
wait_password_state_.srp_B_ = password->srp_B_.as_slice().str();
wait_password_state_.srp_id_ = password->srp_id_;
wait_password_state_.hint_ = std::move(password->hint_);
wait_password_state_.has_recovery_ =
(password->flags_ & telegram_api::account_password::HAS_RECOVERY_MASK) != 0;
wait_password_state_.has_recovery_ = password->has_recovery_;
break;
}
default:

View File

@ -7,6 +7,7 @@
#pragma once
#include "td/telegram/AuthManager.h"
#include "td/telegram/logevent/LogEventHelper.h"
#include "td/telegram/SendCodeHelper.hpp"
#include "td/telegram/Version.h"

View File

@ -6,9 +6,6 @@
//
#include "td/telegram/BackgroundManager.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/AuthManager.h"
#include "td/telegram/BackgroundType.hpp"
#include "td/telegram/ConfigShared.h"
@ -1101,8 +1098,8 @@ std::pair<BackgroundId, BackgroundType> BackgroundManager::on_get_background(
Background background;
background.id = background_id;
background.is_creator = false;
background.is_default = (wallpaper->flags_ & telegram_api::wallPaperNoFile::DEFAULT_MASK) != 0;
background.is_dark = (wallpaper->flags_ & telegram_api::wallPaperNoFile::DARK_MASK) != 0;
background.is_default = wallpaper->default_;
background.is_dark = wallpaper->dark_;
background.type = BackgroundType(true, false, std::move(wallpaper->settings_));
background.name = background.type.get_link();
add_background(background, replace_type);
@ -1127,8 +1124,7 @@ std::pair<BackgroundId, BackgroundType> BackgroundManager::on_get_background(
}
CHECK(document_id == telegram_api::document::ID);
int32 flags = wallpaper->flags_;
bool is_pattern = (flags & telegram_api::wallPaper::PATTERN_MASK) != 0;
bool is_pattern = wallpaper->pattern_;
Document document = td_->documents_manager_->on_get_document(
telegram_api::move_object_as<telegram_api::document>(wallpaper->document_), DialogId(), nullptr,
@ -1142,9 +1138,9 @@ std::pair<BackgroundId, BackgroundType> BackgroundManager::on_get_background(
Background background;
background.id = background_id;
background.access_hash = wallpaper->access_hash_;
background.is_creator = (flags & telegram_api::wallPaper::CREATOR_MASK) != 0;
background.is_default = (flags & telegram_api::wallPaper::DEFAULT_MASK) != 0;
background.is_dark = (flags & telegram_api::wallPaper::DARK_MASK) != 0;
background.is_creator = wallpaper->creator_;
background.is_default = wallpaper->default_;
background.is_dark = wallpaper->dark_;
background.type = BackgroundType(false, is_pattern, std::move(wallpaper->settings_));
background.name = std::move(wallpaper->slug_);
background.file_id = document.file_id;

View File

@ -6,10 +6,6 @@
//
#include "td/telegram/CallActor.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/telegram_api.hpp"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/DhCache.h"
@ -20,6 +16,7 @@
#include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/NotificationManager.h"
#include "td/telegram/Td.h"
#include "td/telegram/telegram_api.hpp"
#include "td/telegram/UpdatesManager.h"
#include "td/utils/algorithm.h"
@ -381,7 +378,7 @@ Status CallActor::do_update_call(telegram_api::phoneCallWaiting &call) {
call_id_ = call.id_;
call_access_hash_ = call.access_hash_;
is_call_id_inited_ = true;
is_video_ |= (call.flags_ & telegram_api::phoneCallWaiting::VIDEO_MASK) != 0;
is_video_ |= call.video_;
call_admin_user_id_ = UserId(call.admin_id_);
// call_participant_user_id_ = UserId(call.participant_id_);
if (call_id_promise_) {
@ -404,7 +401,7 @@ Status CallActor::do_update_call(telegram_api::phoneCallRequested &call) {
call_id_ = call.id_;
call_access_hash_ = call.access_hash_;
is_call_id_inited_ = true;
is_video_ |= (call.flags_ & telegram_api::phoneCallRequested::VIDEO_MASK) != 0;
is_video_ |= call.video_;
call_admin_user_id_ = UserId(call.admin_id_);
// call_participant_user_id_ = UserId(call.participant_id_);
if (call_id_promise_) {
@ -444,7 +441,7 @@ Status CallActor::do_update_call(telegram_api::phoneCallAccepted &call) {
call_id_promise_.set_value(std::move(call.id_));
}
}
is_video_ |= (call.flags_ & telegram_api::phoneCallAccepted::VIDEO_MASK) != 0;
is_video_ |= call.video_;
dh_handshake_.set_g_a(call.g_b_.as_slice());
TRY_STATUS(dh_handshake_.run_checks(true, DhCache::instance()));
std::tie(call_state_.key_fingerprint, call_state_.key) = dh_handshake_.gen_key();
@ -468,7 +465,7 @@ Status CallActor::do_update_call(telegram_api::phoneCall &call) {
}
cancel_timeout();
is_video_ |= (call.flags_ & telegram_api::phoneCall::VIDEO_MASK) != 0;
is_video_ |= call.video_;
LOG(DEBUG) << "Do update call to Ready from state " << static_cast<int32>(state_);
if (state_ == State::WaitAcceptResult) {
@ -487,7 +484,7 @@ Status CallActor::do_update_call(telegram_api::phoneCall &call) {
call_state_.connections.emplace_back(*connection);
}
call_state_.protocol = CallProtocol(*call.protocol_);
call_state_.allow_p2p = (call.flags_ & telegram_api::phoneCall::P2P_ALLOWED_MASK) != 0;
call_state_.allow_p2p = call.p2p_allowed_;
call_state_.type = CallState::Type::Ready;
call_state_need_flush_ = true;

View File

@ -8,7 +8,6 @@
#include "td/telegram/CallActor.h"
#include "td/telegram/CallId.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"

View File

@ -79,8 +79,8 @@ class GetBotCallbackAnswerQuery final : public Td::ResultHandler {
}
auto answer = result_ptr.move_as_ok();
bool show_alert = (answer->flags_ & telegram_api::messages_botCallbackAnswer::ALERT_MASK) != 0;
promise_.set_value(td_api::make_object<td_api::callbackQueryAnswer>(answer->message_, show_alert, answer->url_));
promise_.set_value(
td_api::make_object<td_api::callbackQueryAnswer>(answer->message_, answer->alert_, answer->url_));
}
void on_error(uint64 id, Status status) final {

View File

@ -6,12 +6,11 @@
//
#pragma once
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/DialogId.h"
#include "td/telegram/FullMessageId.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/UserId.h"
#include "td/actor/PromiseFuture.h"

View File

@ -6,8 +6,6 @@
//
#include "td/telegram/ClientActor.h"
#include "td/telegram/td_api.h"
#include "td/telegram/net/NetQueryCounter.h"
#include "td/telegram/net/NetQueryStats.h"
#include "td/telegram/Td.h"

View File

@ -56,18 +56,12 @@ public:
/// of the query or with Telegram.Td.Api.Error as parameter. If it is null, nothing will be called.</param>
/// <exception cref="NullReferenceException">Thrown when query is null.</exception>
void Send(Api::Function^ function, ClientResultHandler^ handler) {
if (function == nullptr) {
throw REF_NEW NullReferenceException("Function can't be null");
}
std::uint64_t queryId = Increment(currentId);
std::uint64_t requestId = Increment(currentRequestId);
if (handler != nullptr) {
handlers[queryId] = handler;
handlers[requestId] = handler;
}
td::Client::Request request;
request.id = queryId;
request.function = td::td_api::move_object_as<td::td_api::Function>(ToUnmanaged(function)->get_object_ptr());
client->send(std::move(request));
auto request = td::td_api::move_object_as<td::td_api::Function>(ToUnmanaged(function)->get_object_ptr());
td::ClientManager::get_manager_singleton()->send(clientId, requestId, std::move(request));
}
/// <summary>
@ -77,31 +71,32 @@ public:
/// <returns>Returns request result.</returns>
/// <exception cref="NullReferenceException">Thrown when query is null.</exception>
static Api::BaseObject^ Execute(Api::Function^ function) {
if (function == nullptr) {
throw REF_NEW NullReferenceException("Function can't be null");
}
td::Client::Request request;
request.id = 0;
request.function = td::td_api::move_object_as<td::td_api::Function>(ToUnmanaged(function)->get_object_ptr());
return Api::FromUnmanaged(*td::Client::execute(std::move(request)).object);
auto request = td::td_api::move_object_as<td::td_api::Function>(ToUnmanaged(function)->get_object_ptr());
return Api::FromUnmanaged(*td::ClientManager::execute(std::move(request)));
}
/// <summary>
/// Launches a cycle which will fetch all results of queries to TDLib and incoming updates from TDLib.
/// Must be called once on a separate dedicated thread, on which all updates and query results will be handled.
/// Returns only when TDLib instance is closed.
/// Must be called once on a separate dedicated thread, on which all updates and query results from all Clients will be handled.
/// Never returns.
/// </summary>
void Run() {
static void Run() {
while (true) {
auto response = client->receive(10.0);
auto response = td::ClientManager::get_manager_singleton()->receive(300.0);
if (response.object != nullptr) {
ProcessResult(response.id, Api::FromUnmanaged(*response.object));
if (response.object->get_id() == td::td_api::updateAuthorizationState::ID &&
bool isClosed = response.object->get_id() == td::td_api::updateAuthorizationState::ID &&
static_cast<td::td_api::updateAuthorizationState &>(*response.object).authorization_state_->get_id() ==
td::td_api::authorizationStateClosed::ID) {
break;
td::td_api::authorizationStateClosed::ID && response.request_id == 0;
ClientResultHandler^ handler;
if (response.request_id == 0 ? updateHandlers.TryGetValue(response.client_id, handler) :
handlers.TryRemove(response.request_id, handler)) {
// TODO try/catch
handler->OnResult(Api::FromUnmanaged(*response.object));
}
if (isClosed) {
updateHandlers.TryRemove(response.client_id, handler);
}
}
}
@ -127,38 +122,33 @@ public:
static void SetLogMessageCallback(std::int32_t max_verbosity_level, LogMessageCallback^ callback) {
std::lock_guard<std::mutex> lock(logMutex);
if (callback == nullptr) {
::td::ClientManager::set_log_message_callback(max_verbosity_level, nullptr);
td::ClientManager::set_log_message_callback(max_verbosity_level, nullptr);
logMessageCallback = nullptr;
} else {
logMessageCallback = callback;
::td::ClientManager::set_log_message_callback(max_verbosity_level, LogMessageCallbackWrapper);
td::ClientManager::set_log_message_callback(max_verbosity_level, LogMessageCallbackWrapper);
}
}
#endif
private:
Client(ClientResultHandler^ updateHandler) {
client = new td::Client();
handlers[0] = updateHandler;
}
~Client() {
delete client;
}
std::int64_t currentId = 0;
ConcurrentDictionary<std::uint64_t, ClientResultHandler^> handlers;
td::Client *client = nullptr;
void ProcessResult(std::uint64_t id, Api::BaseObject^ object) {
ClientResultHandler^ handler;
// update handler stays forever
if (id == 0 ? handlers.TryGetValue(id, handler) : handlers.TryRemove(id, handler)) {
// TODO try/catch
handler->OnResult(object);
clientId = td::ClientManager::get_manager_singleton()->create_client_id();
if (updateHandler != nullptr) {
updateHandlers[clientId] = updateHandler;
}
Send(REF_NEW Api::GetOption("version"), nullptr);
}
#if !TD_CLI
static std::int64_t currentRequestId;
#else
static std::int64_t currentRequestId = 0;
#endif
static ConcurrentDictionary<std::uint64_t, ClientResultHandler^> handlers;
static ConcurrentDictionary<std::int32_t, ClientResultHandler^> updateHandlers;
std::int32_t clientId;
#if !TD_CLI
static std::mutex logMutex;
static LogMessageCallback^ logMessageCallback;
@ -173,6 +163,10 @@ private:
};
#if !TD_CLI
std::int64_t Client::currentRequestId = 0;
ConcurrentDictionary<std::uint64_t, ClientResultHandler^> Client::handlers;
ConcurrentDictionary<std::int32_t, ClientResultHandler^> Client::updateHandlers;
std::mutex Client::logMutex;
LogMessageCallback^ Client::logMessageCallback;
#endif

View File

@ -47,6 +47,7 @@
#include "td/utils/buffer.h"
#include "td/utils/common.h"
#include "td/utils/crypto.h"
#include "td/utils/emoji.h"
#include "td/utils/format.h"
#include "td/utils/JsonBuilder.h"
#include "td/utils/logging.h"
@ -959,6 +960,16 @@ void ConfigManager::lazy_request_config() {
set_timeout_at(expire_time_.at());
}
void ConfigManager::try_request_app_config() {
if (get_app_config_queries_.size() + reget_app_config_queries_.size() != 1) {
return;
}
auto query = G()->net_query_creator().create_unauth(telegram_api::help_getAppConfig());
query->total_timeout_limit_ = 60 * 60 * 24;
G()->net_query_dispatcher().dispatch_with_callback(std::move(query), actor_shared(this, 1));
}
void ConfigManager::get_app_config(Promise<td_api::object_ptr<td_api::JsonValue>> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
@ -968,11 +979,21 @@ void ConfigManager::get_app_config(Promise<td_api::object_ptr<td_api::JsonValue>
}
get_app_config_queries_.push_back(std::move(promise));
if (get_app_config_queries_.size() == 1) {
auto query = G()->net_query_creator().create_unauth(telegram_api::help_getAppConfig());
query->total_timeout_limit_ = 60 * 60 * 24;
G()->net_query_dispatcher().dispatch_with_callback(std::move(query), actor_shared(this, 1));
try_request_app_config();
}
void ConfigManager::reget_app_config(Promise<Unit> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
auto auth_manager = G()->td().get_actor_unsafe()->auth_manager_.get();
if (auth_manager != nullptr && auth_manager->is_bot()) {
return promise.set_value(Unit());
}
reget_app_config_queries_.push_back(std::move(promise));
try_request_app_config();
}
void ConfigManager::get_content_settings(Promise<Unit> &&promise) {
@ -1065,7 +1086,7 @@ void ConfigManager::do_set_ignore_sensitive_content_restrictions(bool ignore_sen
ignore_sensitive_content_restrictions);
bool have_ignored_restriction_reasons = G()->shared_config().have_option("ignored_restriction_reasons");
if (have_ignored_restriction_reasons != ignore_sensitive_content_restrictions) {
get_app_config(Auto());
reget_app_config(Auto());
}
}
@ -1121,7 +1142,7 @@ void ConfigManager::on_result(NetQueryPtr res) {
return;
}
remove_suggested_action(suggested_actions_, suggested_action);
get_app_config(Auto());
reget_app_config(Auto());
for (auto &promise : promises) {
promise.set_value(Unit());
@ -1245,15 +1266,16 @@ void ConfigManager::on_result(NetQueryPtr res) {
if (token == 1) {
auto promises = std::move(get_app_config_queries_);
get_app_config_queries_.clear();
CHECK(!promises.empty());
auto unit_promises = std::move(reget_app_config_queries_);
reget_app_config_queries_.clear();
CHECK(!promises.empty() || !unit_promises.empty());
auto result_ptr = fetch_result<telegram_api::help_getAppConfig>(std::move(res));
if (result_ptr.is_error()) {
for (auto &promise : promises) {
if (!promise) {
promise.set_value(nullptr);
} else {
promise.set_error(result_ptr.error().clone());
}
promise.set_error(result_ptr.error().clone());
}
for (auto &promise : unit_promises) {
promise.set_error(result_ptr.error().clone());
}
return;
}
@ -1261,11 +1283,10 @@ void ConfigManager::on_result(NetQueryPtr res) {
auto result = result_ptr.move_as_ok();
process_app_config(result);
for (auto &promise : promises) {
if (!promise) {
promise.set_value(nullptr);
} else {
promise.set_value(convert_json_value_object(result));
}
promise.set_value(convert_json_value_object(result));
}
for (auto &promise : unit_promises) {
promise.set_value(Unit());
}
return;
}
@ -1318,7 +1339,7 @@ void ConfigManager::save_config_expire(Timestamp timestamp) {
}
void ConfigManager::process_config(tl_object_ptr<telegram_api::config> config) {
bool is_from_main_dc = G()->net_query_dispatcher().main_dc_id().get_value() == config->this_dc_;
bool is_from_main_dc = G()->net_query_dispatcher().get_main_dc_id().get_value() == config->this_dc_;
LOG(INFO) << to_string(config);
auto reload_in = clamp(config->expires_ - config->date_, 60, 86400);
@ -1348,8 +1369,7 @@ void ConfigManager::process_config(tl_object_ptr<telegram_api::config> config) {
shared_config.set_option_integer("pinned_chat_count_max", config->pinned_dialogs_count_max_);
shared_config.set_option_integer("pinned_archived_chat_count_max", config->pinned_infolder_count_max_);
if (is_from_main_dc || !shared_config.have_option("expect_blocking")) {
shared_config.set_option_boolean("expect_blocking",
(config->flags_ & telegram_api::config::BLOCKED_MODE_MASK) != 0);
shared_config.set_option_boolean("expect_blocking", config->blocked_mode_);
}
if (is_from_main_dc || !shared_config.have_option("dc_txt_domain_name")) {
shared_config.set_option_string("dc_txt_domain_name", config->dc_txt_domain_name_);
@ -1383,8 +1403,7 @@ void ConfigManager::process_config(tl_object_ptr<telegram_api::config> config) {
if (is_from_main_dc) {
shared_config.set_option_integer("edit_time_limit", config->edit_time_limit_);
shared_config.set_option_boolean("revoke_pm_inbox",
(config->flags_ & telegram_api::config::REVOKE_PM_INBOX_MASK) != 0);
shared_config.set_option_boolean("revoke_pm_inbox", config->revoke_pm_inbox_);
shared_config.set_option_integer("revoke_time_limit", config->revoke_time_limit_);
shared_config.set_option_integer("revoke_pm_time_limit", config->revoke_pm_time_limit_);
@ -1451,7 +1470,7 @@ void ConfigManager::process_config(tl_object_ptr<telegram_api::config> config) {
// shared_config.set_option_integer("push_chat_limit", config->push_chat_limit_);
if (is_from_main_dc) {
get_app_config(Auto());
reget_app_config(Auto());
if (!shared_config.have_option("can_ignore_sensitive_content_restrictions") ||
!shared_config.have_option("ignore_sensitive_content_restrictions")) {
get_content_settings(Auto());
@ -1478,12 +1497,14 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
vector<string> dice_emojis;
std::unordered_map<string, size_t> dice_emoji_index;
std::unordered_map<string, string> dice_emoji_success_value;
vector<string> emoji_sounds;
string animation_search_provider;
string animation_search_emojis;
vector<SuggestedAction> suggested_actions;
bool can_archive_and_mute_new_chats_from_unknown_users = false;
int64 chat_read_mark_expire_period = 0;
int64 chat_read_mark_size_threshold = 0;
double animated_emoji_zoom = 0.0;
if (config->get_id() == telegram_api::jsonObject::ID) {
for (auto &key_value : static_cast<telegram_api::jsonObject *>(config.get())->value_) {
Slice key = key_value->key_;
@ -1511,6 +1532,10 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
}
continue;
}
if (key == "emojies_animated_zoom") {
animated_emoji_zoom = get_json_value_double(std::move(key_value->value_), "emojies_animated_zoom");
continue;
}
if (key == "emojies_send_dice") {
if (value->get_id() == telegram_api::jsonArray::ID) {
auto emojis = std::move(static_cast<telegram_api::jsonArray *>(value)->value_);
@ -1563,6 +1588,46 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
}
continue;
}
if (key == "emojies_sounds") {
if (value->get_id() == telegram_api::jsonObject::ID) {
auto sounds = std::move(static_cast<telegram_api::jsonObject *>(value)->value_);
for (auto &sound : sounds) {
CHECK(sound != nullptr);
if (sound->value_->get_id() == telegram_api::jsonObject::ID) {
string id;
string access_hash;
string file_reference_base64;
for (auto &sound_key_value : static_cast<telegram_api::jsonObject *>(sound->value_.get())->value_) {
if (sound_key_value->value_->get_id() != telegram_api::jsonString::ID) {
continue;
}
auto current_value = get_json_value_string(std::move(sound_key_value->value_), Slice());
if (sound_key_value->key_ == "id") {
id = std::move(current_value);
}
if (sound_key_value->key_ == "access_hash") {
access_hash = std::move(current_value);
}
if (sound_key_value->key_ == "file_reference_base64") {
file_reference_base64 = std::move(current_value);
}
}
if (to_integer_safe<int64>(id).is_error() || to_integer_safe<int64>(access_hash).is_error() ||
!is_base64url(file_reference_base64) || !is_emoji(sound->key_)) {
LOG(ERROR) << "Receive unexpected sound value " << to_string(sound);
} else {
emoji_sounds.push_back(sound->key_);
emoji_sounds.push_back(PSTRING() << id << ':' << access_hash << ':' << file_reference_base64);
}
} else {
LOG(ERROR) << "Receive unexpected emoji sound " << to_string(sound);
}
}
} else {
LOG(ERROR) << "Receive unexpected emojies_sounds " << to_string(*value);
}
continue;
}
if (key == "gif_search_branding") {
animation_search_provider = get_json_value_string(std::move(key_value->value_), "gif_search_branding");
continue;
@ -1722,6 +1787,13 @@ void ConfigManager::process_app_config(tl_object_ptr<telegram_api::JSONValue> &c
shared_config.set_option_string("dice_emojis", implode(dice_emojis, '\x01'));
}
shared_config.set_option_string("emoji_sounds", implode(emoji_sounds, ','));
if (animated_emoji_zoom <= 0 || animated_emoji_zoom > 2.0) {
shared_config.set_option_empty("animated_emoji_zoom");
} else {
shared_config.set_option_integer("animated_emoji_zoom", static_cast<int64>(animated_emoji_zoom * 1e9));
}
if (animation_search_provider.empty()) {
shared_config.set_option_empty("animation_search_provider");
} else {

View File

@ -10,7 +10,6 @@
#include "td/telegram/net/DcOptions.h"
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/SuggestedAction.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
@ -88,6 +87,8 @@ class ConfigManager final : public NetQueryCallback {
void get_app_config(Promise<td_api::object_ptr<td_api::JsonValue>> &&promise);
void reget_app_config(Promise<Unit> &&promise);
void get_content_settings(Promise<Unit> &&promise);
void set_content_settings(bool ignore_sensitive_content_restrictions, Promise<Unit> &&promise);
@ -114,6 +115,7 @@ class ConfigManager final : public NetQueryCallback {
FloodControlStrict lazy_request_flood_control_;
vector<Promise<td_api::object_ptr<td_api::JsonValue>>> get_app_config_queries_;
vector<Promise<Unit>> reget_app_config_queries_;
vector<Promise<Unit>> get_content_settings_queries_;
vector<Promise<Unit>> set_content_settings_queries_[2];
@ -142,6 +144,8 @@ class ConfigManager final : public NetQueryCallback {
void request_config_from_dc_impl(DcId dc_id);
void process_config(tl_object_ptr<telegram_api::config> config);
void try_request_app_config();
void process_app_config(tl_object_ptr<telegram_api::JSONValue> &config);
void do_set_ignore_sensitive_content_restrictions(bool ignore_sensitive_content_restrictions);

View File

@ -1611,7 +1611,8 @@ class ExportChatInviteQuery final : public Td::ResultHandler {
: promise_(std::move(promise)) {
}
void send(DialogId dialog_id, int32 expire_date, int32 usage_limit, bool is_permanent) {
void send(DialogId dialog_id, const string &title, int32 expire_date, int32 usage_limit, bool creates_join_request,
bool is_permanent) {
dialog_id_ = dialog_id;
auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
if (input_peer == nullptr) {
@ -1625,12 +1626,18 @@ class ExportChatInviteQuery final : public Td::ResultHandler {
if (usage_limit > 0) {
flags |= telegram_api::messages_exportChatInvite::USAGE_LIMIT_MASK;
}
if (creates_join_request) {
flags |= telegram_api::messages_exportChatInvite::REQUEST_NEEDED_MASK;
}
if (is_permanent) {
flags |= telegram_api::messages_exportChatInvite::LEGACY_REVOKE_PERMANENT_MASK;
}
if (!title.empty()) {
flags |= telegram_api::messages_exportChatInvite::TITLE_MASK;
}
send_query(G()->net_query_creator().create(telegram_api::messages_exportChatInvite(
flags, false /*ignored*/, std::move(input_peer), expire_date, usage_limit)));
flags, false /*ignored*/, false /*ignored*/, std::move(input_peer), expire_date, usage_limit, title)));
}
void on_result(uint64 id, BufferSlice packet) final {
@ -1670,7 +1677,8 @@ class EditChatInviteLinkQuery final : public Td::ResultHandler {
: promise_(std::move(promise)) {
}
void send(DialogId dialog_id, const string &invite_link, int32 expire_date, int32 usage_limit) {
void send(DialogId dialog_id, const string &invite_link, const string &title, int32 expire_date, int32 usage_limit,
bool creates_join_request) {
dialog_id_ = dialog_id;
auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
if (input_peer == nullptr) {
@ -1678,9 +1686,12 @@ class EditChatInviteLinkQuery final : public Td::ResultHandler {
}
int32 flags = telegram_api::messages_editExportedChatInvite::EXPIRE_DATE_MASK |
telegram_api::messages_editExportedChatInvite::USAGE_LIMIT_MASK;
send_query(G()->net_query_creator().create(telegram_api::messages_editExportedChatInvite(
flags, false /*ignored*/, std::move(input_peer), invite_link, expire_date, usage_limit)));
telegram_api::messages_editExportedChatInvite::USAGE_LIMIT_MASK |
telegram_api::messages_editExportedChatInvite::REQUEST_NEEDED_MASK |
telegram_api::messages_editExportedChatInvite::TITLE_MASK;
send_query(G()->net_query_creator().create(
telegram_api::messages_editExportedChatInvite(flags, false /*ignored*/, std::move(input_peer), invite_link,
expire_date, usage_limit, creates_join_request, title)));
}
void on_result(uint64 id, BufferSlice packet) final {
@ -1902,8 +1913,10 @@ class GetChatInviteImportersQuery final : public Td::ResultHandler {
input_user = make_tl_object<telegram_api::inputUserEmpty>();
}
send_query(G()->net_query_creator().create(telegram_api::messages_getChatInviteImporters(
std::move(input_peer), invite_link, offset_date, std::move(input_user), limit)));
int32 flags = telegram_api::messages_getChatInviteImporters::LINK_MASK;
send_query(G()->net_query_creator().create(
telegram_api::messages_getChatInviteImporters(flags, false /*ignored*/, std::move(input_peer), invite_link,
string(), offset_date, std::move(input_user), limit)));
}
void on_result(uint64 id, BufferSlice packet) final {
@ -1925,13 +1938,16 @@ class GetChatInviteImportersQuery final : public Td::ResultHandler {
vector<td_api::object_ptr<td_api::chatInviteLinkMember>> invite_link_members;
for (auto &importer : result->importers_) {
UserId user_id(importer->user_id_);
if (!user_id.is_valid()) {
LOG(ERROR) << "Receive invalid invite link " << user_id << " in " << dialog_id_;
UserId approver_user_id(importer->approved_by_);
if (!user_id.is_valid() || (!approver_user_id.is_valid() && approver_user_id != UserId()) ||
importer->requested_) {
LOG(ERROR) << "Receive invalid invite link importer: " << to_string(importer);
total_count--;
continue;
}
invite_link_members.push_back(td_api::make_object<td_api::chatInviteLinkMember>(
td->contacts_manager_->get_user_id_object(user_id, "chatInviteLinkMember"), importer->date_));
td->contacts_manager_->get_user_id_object(user_id, "chatInviteLinkMember"), importer->date_,
td->contacts_manager_->get_user_id_object(approver_user_id, "chatInviteLinkMember")));
}
promise_.set_value(td_api::make_object<td_api::chatInviteLinkMembers>(total_count, std::move(invite_link_members)));
}
@ -1942,6 +1958,128 @@ class GetChatInviteImportersQuery final : public Td::ResultHandler {
}
};
class GetChatJoinRequestsQuery final : public Td::ResultHandler {
Promise<td_api::object_ptr<td_api::chatJoinRequests>> promise_;
DialogId dialog_id_;
public:
explicit GetChatJoinRequestsQuery(Promise<td_api::object_ptr<td_api::chatJoinRequests>> &&promise)
: promise_(std::move(promise)) {
}
void send(DialogId dialog_id, const string &invite_link, const string &query, int32 offset_date,
UserId offset_user_id, int32 limit) {
dialog_id_ = dialog_id;
auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
if (input_peer == nullptr) {
return on_error(0, Status::Error(400, "Can't access the chat"));
}
auto input_user = td->contacts_manager_->get_input_user(offset_user_id);
if (input_user == nullptr) {
input_user = make_tl_object<telegram_api::inputUserEmpty>();
}
int32 flags = telegram_api::messages_getChatInviteImporters::REQUESTED_MASK;
if (!invite_link.empty()) {
flags |= telegram_api::messages_getChatInviteImporters::LINK_MASK;
}
if (!query.empty()) {
flags |= telegram_api::messages_getChatInviteImporters::Q_MASK;
}
send_query(G()->net_query_creator().create(
telegram_api::messages_getChatInviteImporters(flags, false /*ignored*/, std::move(input_peer), invite_link,
query, offset_date, std::move(input_user), limit)));
}
void on_result(uint64 id, BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::messages_getChatInviteImporters>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
auto result = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for GetChatJoinRequestsQuery: " << to_string(result);
td->contacts_manager_->on_get_users(std::move(result->users_), "GetChatJoinRequestsQuery");
int32 total_count = result->count_;
if (total_count < static_cast<int32>(result->importers_.size())) {
LOG(ERROR) << "Receive wrong total count of join requests " << total_count << " in " << dialog_id_;
total_count = static_cast<int32>(result->importers_.size());
}
vector<td_api::object_ptr<td_api::chatJoinRequest>> join_requests;
vector<int64> recent_requesters;
for (auto &request : result->importers_) {
UserId user_id(request->user_id_);
UserId approver_user_id(request->approved_by_);
if (!user_id.is_valid() || approver_user_id.is_valid() || !request->requested_) {
LOG(ERROR) << "Receive invalid join request: " << to_string(request);
total_count--;
continue;
}
if (recent_requesters.size() < 3) {
recent_requesters.push_back(user_id.get());
}
join_requests.push_back(td_api::make_object<td_api::chatJoinRequest>(
td->contacts_manager_->get_user_id_object(user_id, "chatJoinRequest"), request->date_, request->about_));
}
td->messages_manager_->on_update_dialog_pending_join_requests(dialog_id_, total_count,
std::move(recent_requesters));
promise_.set_value(td_api::make_object<td_api::chatJoinRequests>(total_count, std::move(join_requests)));
}
void on_error(uint64 id, Status status) final {
td->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetChatJoinRequestsQuery");
promise_.set_error(std::move(status));
}
};
class HideChatJoinRequestQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
DialogId dialog_id_;
public:
explicit HideChatJoinRequestQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(DialogId dialog_id, UserId user_id, bool is_approved) {
dialog_id_ = dialog_id;
auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
if (input_peer == nullptr) {
return on_error(0, Status::Error(400, "Can't access the chat"));
}
auto input_user = td->contacts_manager_->get_input_user(user_id);
if (input_user == nullptr) {
return on_error(0, Status::Error(400, "Can't find user"));
}
int32 flags = 0;
if (is_approved) {
flags |= telegram_api::messages_hideChatJoinRequest::APPROVED_MASK;
}
send_query(G()->net_query_creator().create(telegram_api::messages_hideChatJoinRequest(
flags, false /*ignored*/, std::move(input_peer), std::move(input_user))));
}
void on_result(uint64 id, BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::messages_hideChatJoinRequest>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
auto result = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for HideChatJoinRequestQuery: " << to_string(result);
td->updates_manager_->on_get_updates(std::move(result), std::move(promise_));
}
void on_error(uint64 id, Status status) final {
td->messages_manager_->on_get_dialog_error(dialog_id_, status, "HideChatJoinRequestQuery");
promise_.set_error(std::move(status));
}
};
class RevokeChatInviteLinkQuery final : public Td::ResultHandler {
Promise<td_api::object_ptr<td_api::chatInviteLinks>> promise_;
DialogId dialog_id_;
@ -1960,7 +2098,7 @@ class RevokeChatInviteLinkQuery final : public Td::ResultHandler {
int32 flags = telegram_api::messages_editExportedChatInvite::REVOKED_MASK;
send_query(G()->net_query_creator().create(telegram_api::messages_editExportedChatInvite(
flags, false /*ignored*/, std::move(input_peer), invite_link, 0, 0)));
flags, false /*ignored*/, std::move(input_peer), invite_link, 0, 0, false, string())));
}
void on_result(uint64 id, BufferSlice packet) final {
@ -5176,15 +5314,11 @@ void ContactsManager::get_account_ttl(Promise<int32> &&promise) const {
td_api::object_ptr<td_api::session> ContactsManager::convert_authorization_object(
tl_object_ptr<telegram_api::authorization> &&authorization) {
CHECK(authorization != nullptr);
bool is_current = (authorization->flags_ & telegram_api::authorization::CURRENT_MASK) != 0;
bool is_official_application = (authorization->flags_ & telegram_api::authorization::OFFICIAL_APP_MASK) != 0;
bool is_password_pending = (authorization->flags_ & telegram_api::authorization::PASSWORD_PENDING_MASK) != 0;
return td_api::make_object<td_api::session>(
authorization->hash_, is_current, is_password_pending, authorization->api_id_, authorization->app_name_,
authorization->app_version_, is_official_application, authorization->device_model_, authorization->platform_,
authorization->system_version_, authorization->date_created_, authorization->date_active_, authorization->ip_,
authorization->country_, authorization->region_);
authorization->hash_, authorization->current_, authorization->password_pending_, authorization->api_id_,
authorization->app_name_, authorization->app_version_, authorization->official_app_, authorization->device_model_,
authorization->platform_, authorization->system_version_, authorization->date_created_,
authorization->date_active_, authorization->ip_, authorization->country_, authorization->region_);
}
void ContactsManager::confirm_qr_code_authentication(const string &link,
@ -5765,20 +5899,6 @@ void ContactsManager::search_dialogs_nearby(const Location &location,
td_->create_handler<SearchDialogsNearbyQuery>(std::move(query_promise))->send(location, false, -1);
}
void ContactsManager::set_location(const Location &location, Promise<Unit> &&promise) {
if (location.empty()) {
return promise.set_error(Status::Error(400, "Invalid location specified"));
}
last_user_location_ = location;
try_send_set_location_visibility_query();
auto query_promise = PromiseCreator::lambda(
[promise = std::move(promise)](Result<tl_object_ptr<telegram_api::Updates>> result) mutable {
promise.set_value(Unit());
});
td_->create_handler<SearchDialogsNearbyQuery>(std::move(query_promise))->send(location, true, -1);
}
vector<td_api::object_ptr<td_api::chatNearby>> ContactsManager::get_chats_nearby_object(
const vector<DialogNearby> &dialogs_nearby) {
return transform(dialogs_nearby, [](const DialogNearby &dialog_nearby) {
@ -5841,6 +5961,20 @@ void ContactsManager::on_get_dialogs_nearby(Result<tl_object_ptr<telegram_api::U
get_chats_nearby_object(channels_nearby_)));
}
void ContactsManager::set_location(const Location &location, Promise<Unit> &&promise) {
if (location.empty()) {
return promise.set_error(Status::Error(400, "Invalid location specified"));
}
last_user_location_ = location;
try_send_set_location_visibility_query();
auto query_promise = PromiseCreator::lambda(
[promise = std::move(promise)](Result<tl_object_ptr<telegram_api::Updates>> result) mutable {
promise.set_value(Unit());
});
td_->create_handler<SearchDialogsNearbyQuery>(std::move(query_promise))->send(location, true, -1);
}
void ContactsManager::set_location_visibility() {
bool is_location_visible = G()->shared_config().get_option_boolean("is_location_visible");
auto pending_location_visibility_expire_date = is_location_visible ? std::numeric_limits<int32>::max() : 0;
@ -5908,6 +6042,53 @@ void ContactsManager::on_set_location_visibility_expire_date(int32 set_expire_da
update_is_location_visible();
}
void ContactsManager::get_is_location_visible(Promise<Unit> &&promise) {
auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), promise = std::move(promise)](
Result<tl_object_ptr<telegram_api::Updates>> result) mutable {
send_closure(actor_id, &ContactsManager::on_get_is_location_visible, std::move(result), std::move(promise));
});
td_->create_handler<SearchDialogsNearbyQuery>(std::move(query_promise))->send(Location(), true, -1);
}
void ContactsManager::on_get_is_location_visible(Result<tl_object_ptr<telegram_api::Updates>> &&result,
Promise<Unit> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
if (result.is_error()) {
if (result.error().message() == "GEO_POINT_INVALID" && pending_location_visibility_expire_date_ == -1 &&
location_visibility_expire_date_ > 0) {
set_location_visibility_expire_date(0);
update_is_location_visible();
}
return promise.set_value(Unit());
}
auto updates_ptr = result.move_as_ok();
if (updates_ptr->get_id() != telegram_api::updates::ID) {
LOG(ERROR) << "Receive " << oneline(to_string(*updates_ptr)) << " instead of updates";
return promise.set_value(Unit());
}
auto updates = std::move(telegram_api::move_object_as<telegram_api::updates>(updates_ptr)->updates_);
if (updates.size() != 1 || updates[0]->get_id() != telegram_api::updatePeerLocated::ID) {
LOG(ERROR) << "Receive unexpected " << to_string(updates);
return promise.set_value(Unit());
}
auto peers = std::move(static_cast<telegram_api::updatePeerLocated *>(updates[0].get())->peers_);
if (peers.size() != 1 || peers[0]->get_id() != telegram_api::peerSelfLocated::ID) {
LOG(ERROR) << "Receive unexpected " << to_string(peers);
return promise.set_value(Unit());
}
auto location_visibility_expire_date = static_cast<telegram_api::peerSelfLocated *>(peers[0].get())->expires_;
if (location_visibility_expire_date != location_visibility_expire_date_) {
set_location_visibility_expire_date(location_visibility_expire_date);
update_is_location_visible();
}
promise.set_value(Unit());
}
int32 ContactsManager::on_update_peer_located(vector<tl_object_ptr<telegram_api::PeerLocated>> &&peers,
bool from_update) {
auto now = G()->unix_time();
@ -6012,6 +6193,7 @@ void ContactsManager::set_location_visibility_expire_date(int32 expire_date) {
} else {
G()->td_db()->get_binlog_pmc()->set("location_visibility_expire_date", to_string(expire_date));
}
// the caller must call update_is_location_visible() itself
}
void ContactsManager::update_is_location_visible() {
@ -7258,41 +7440,52 @@ Status ContactsManager::can_manage_dialog_invite_links(DialogId dialog_id, bool
return Status::OK();
}
void ContactsManager::export_dialog_invite_link(DialogId dialog_id, int32 expire_date, int32 usage_limit,
bool is_permanent,
void ContactsManager::export_dialog_invite_link(DialogId dialog_id, string title, int32 expire_date, int32 usage_limit,
bool creates_join_request, bool is_permanent,
Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise) {
get_me(PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, expire_date, usage_limit, is_permanent,
get_me(PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, title = std::move(title), expire_date,
usage_limit, creates_join_request, is_permanent,
promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
send_closure(actor_id, &ContactsManager::export_dialog_invite_link_impl, dialog_id, expire_date, usage_limit,
is_permanent, std::move(promise));
send_closure(actor_id, &ContactsManager::export_dialog_invite_link_impl, dialog_id, std::move(title), expire_date,
usage_limit, creates_join_request, is_permanent, std::move(promise));
}
}));
}
void ContactsManager::export_dialog_invite_link_impl(DialogId dialog_id, int32 expire_date, int32 usage_limit,
bool is_permanent,
void ContactsManager::export_dialog_invite_link_impl(DialogId dialog_id, string title, int32 expire_date,
int32 usage_limit, bool creates_join_request, bool is_permanent,
Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id));
if (creates_join_request && usage_limit > 0) {
return promise.set_error(
Status::Error(400, "Member limit can't be specified for links requiring administrator approval"));
}
auto new_title = clean_name(std::move(title), MAX_INVITE_LINK_TITLE_LENGTH);
td_->create_handler<ExportChatInviteQuery>(std::move(promise))
->send(dialog_id, expire_date, usage_limit, is_permanent);
->send(dialog_id, new_title, expire_date, usage_limit, creates_join_request, is_permanent);
}
void ContactsManager::edit_dialog_invite_link(DialogId dialog_id, const string &invite_link, int32 expire_date,
int32 usage_limit,
void ContactsManager::edit_dialog_invite_link(DialogId dialog_id, const string &invite_link, string title,
int32 expire_date, int32 usage_limit, bool creates_join_request,
Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise) {
TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id));
if (creates_join_request && usage_limit > 0) {
return promise.set_error(
Status::Error(400, "Member limit can't be specified for links requiring administrator approval"));
}
if (invite_link.empty()) {
return promise.set_error(Status::Error(400, "Invite link must be non-empty"));
}
auto new_title = clean_name(std::move(title), MAX_INVITE_LINK_TITLE_LENGTH);
td_->create_handler<EditChatInviteLinkQuery>(std::move(promise))
->send(dialog_id, invite_link, expire_date, usage_limit);
->send(dialog_id, invite_link, new_title, expire_date, creates_join_request, usage_limit);
}
void ContactsManager::get_dialog_invite_link(DialogId dialog_id, const string &invite_link,
@ -7354,6 +7547,32 @@ void ContactsManager::get_dialog_invite_link_users(
->send(dialog_id, invite_link, offset_date, offset_user_id, limit);
}
void ContactsManager::get_dialog_join_requests(DialogId dialog_id, const string &invite_link, const string &query,
td_api::object_ptr<td_api::chatJoinRequest> offset_request, int32 limit,
Promise<td_api::object_ptr<td_api::chatJoinRequests>> &&promise) {
TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id));
if (limit <= 0) {
return promise.set_error(Status::Error(400, "Parameter limit must be positive"));
}
UserId offset_user_id;
int32 offset_date = 0;
if (offset_request != nullptr) {
offset_user_id = UserId(offset_request->user_id_);
offset_date = offset_request->date_;
}
td_->create_handler<GetChatJoinRequestsQuery>(std::move(promise))
->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,
Promise<Unit> &&promise) {
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);
}
void ContactsManager::revoke_dialog_invite_link(DialogId dialog_id, const string &invite_link,
Promise<td_api::object_ptr<td_api::chatInviteLinks>> &&promise) {
TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id));
@ -8484,8 +8703,7 @@ ContactsManager::User *ContactsManager::get_user_force(UserId user_id) {
if ((u == nullptr || !u->is_received) &&
(user_id == get_service_notifications_user_id() || user_id == get_replies_bot_user_id() ||
user_id == get_anonymous_bot_user_id())) {
int32 flags = telegram_api::user::ACCESS_HASH_MASK | telegram_api::user::FIRST_NAME_MASK |
telegram_api::user::APPLY_MIN_PHOTO_MASK;
int32 flags = USER_FLAG_HAS_ACCESS_HASH | USER_FLAG_HAS_FIRST_NAME | USER_FLAG_NEED_APPLY_MIN_PHOTO;
int64 profile_photo_id = 0;
int32 profile_photo_dc_id = 1;
string first_name;
@ -8495,26 +8713,26 @@ ContactsManager::User *ContactsManager::get_user_force(UserId user_id) {
int32 bot_info_version = 0;
if (user_id == get_service_notifications_user_id()) {
flags |= telegram_api::user::PHONE_MASK | telegram_api::user::VERIFIED_MASK | telegram_api::user::SUPPORT_MASK;
flags |= USER_FLAG_HAS_PHONE_NUMBER | USER_FLAG_IS_VERIFIED | USER_FLAG_IS_SUPPORT;
first_name = "Telegram";
if (G()->is_test_dc()) {
flags |= telegram_api::user::LAST_NAME_MASK;
flags |= USER_FLAG_HAS_LAST_NAME;
last_name = "Notifications";
}
phone_number = "42777";
profile_photo_id = 3337190045231023;
} else if (user_id == get_replies_bot_user_id()) {
flags |= telegram_api::user::USERNAME_MASK | telegram_api::user::BOT_MASK;
flags |= USER_FLAG_HAS_USERNAME | USER_FLAG_IS_BOT;
if (!G()->is_test_dc()) {
flags |= telegram_api::user::BOT_NOCHATS_MASK;
flags |= USER_FLAG_IS_PRIVATE_BOT;
}
first_name = "Replies";
username = "replies";
bot_info_version = G()->is_test_dc() ? 1 : 3;
} else if (user_id == get_anonymous_bot_user_id()) {
flags |= telegram_api::user::USERNAME_MASK | telegram_api::user::BOT_MASK;
flags |= USER_FLAG_HAS_USERNAME | USER_FLAG_IS_BOT;
if (!G()->is_test_dc()) {
flags |= telegram_api::user::BOT_NOCHATS_MASK;
flags |= USER_FLAG_IS_PRIVATE_BOT;
}
first_name = "Group";
username = G()->is_test_dc() ? "izgroupbot" : "GroupAnonymousBot";
@ -8524,7 +8742,6 @@ ContactsManager::User *ContactsManager::get_user_force(UserId user_id) {
telegram_api::object_ptr<telegram_api::userProfilePhoto> profile_photo;
if (!G()->is_test_dc() && profile_photo_id != 0) {
flags |= telegram_api::user::PHOTO_MASK;
profile_photo = telegram_api::make_object<telegram_api::userProfilePhoto>(0, false /*ignored*/, profile_photo_id,
BufferSlice(), profile_photo_dc_id);
}
@ -9776,20 +9993,26 @@ void ContactsManager::update_chat(Chat *c, ChatId chat_id, bool from_binlog, boo
if (c->is_photo_changed) {
td_->messages_manager_->on_dialog_photo_updated(DialogId(chat_id));
drop_chat_photos(chat_id, !c->photo.small_file_id.is_valid(), true, "update_chat");
c->is_photo_changed = false;
}
if (c->is_title_changed) {
td_->messages_manager_->on_dialog_title_updated(DialogId(chat_id));
c->is_title_changed = false;
}
if (c->is_default_permissions_changed) {
td_->messages_manager_->on_dialog_permissions_updated(DialogId(chat_id));
c->is_default_permissions_changed = false;
}
if (c->is_is_active_changed) {
update_dialogs_for_discussion(DialogId(chat_id), c->is_active && c->status.is_creator());
c->is_is_active_changed = false;
}
if (c->is_status_changed) {
if (!c->status.can_manage_invite_links()) {
td_->messages_manager_->drop_dialog_pending_join_requests(DialogId(chat_id));
}
c->is_status_changed = false;
}
c->is_photo_changed = false;
c->is_title_changed = false;
c->is_default_permissions_changed = false;
c->is_is_active_changed = false;
LOG(DEBUG) << "Update " << chat_id << ": need_save_to_database = " << c->need_save_to_database
<< ", is_changed = " << c->is_changed;
@ -9825,9 +10048,11 @@ void ContactsManager::update_channel(Channel *c, ChannelId channel_id, bool from
if (c->is_photo_changed) {
td_->messages_manager_->on_dialog_photo_updated(DialogId(channel_id));
drop_channel_photos(channel_id, !c->photo.small_file_id.is_valid(), true, "update_channel");
c->is_photo_changed = false;
}
if (c->is_title_changed) {
td_->messages_manager_->on_dialog_title_updated(DialogId(channel_id));
c->is_title_changed = false;
}
if (c->is_status_changed) {
c->status.update_restrictions();
@ -9849,6 +10074,10 @@ void ContactsManager::update_channel(Channel *c, ChannelId channel_id, bool from
if (!c->status.is_member()) {
remove_inactive_channel(channel_id);
}
if (!c->status.can_manage_invite_links()) {
td_->messages_manager_->drop_dialog_pending_join_requests(DialogId(channel_id));
}
c->is_status_changed = false;
}
if (c->is_username_changed) {
if (c->status.is_creator() && created_public_channels_inited_[0]) {
@ -9860,6 +10089,7 @@ void ContactsManager::update_channel(Channel *c, ChannelId channel_id, bool from
}
}
}
c->is_username_changed = false;
}
if (c->is_default_permissions_changed) {
td_->messages_manager_->on_dialog_permissions_updated(DialogId(channel_id));
@ -9867,6 +10097,7 @@ void ContactsManager::update_channel(Channel *c, ChannelId channel_id, bool from
RestrictedRights(false, false, false, false, false, false, false, false, false, false, false)) {
remove_dialog_suggested_action(SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)});
}
c->is_default_permissions_changed = false;
}
if (!td_->auth_manager_->is_bot()) {
if (c->restriction_reasons.empty()) {
@ -9876,12 +10107,6 @@ void ContactsManager::update_channel(Channel *c, ChannelId channel_id, bool from
}
}
c->is_photo_changed = false;
c->is_title_changed = false;
c->is_default_permissions_changed = false;
c->is_status_changed = false;
c->is_username_changed = false;
LOG(DEBUG) << "Update " << channel_id << ": need_save_to_database = " << c->need_save_to_database
<< ", is_changed = " << c->is_changed;
c->need_save_to_database |= c->is_changed;
@ -10175,8 +10400,8 @@ void ContactsManager::on_get_user_full(tl_object_ptr<telegram_api::userFull> &&u
}
on_update_user_full_common_chat_count(user_full, user_id, user->common_chats_count_);
on_update_user_full_need_phone_number_privacy_exception(
user_full, user_id, (user->settings_->flags_ & telegram_api::peerSettings::NEED_CONTACTS_EXCEPTION_MASK) != 0);
on_update_user_full_need_phone_number_privacy_exception(user_full, user_id,
user->settings_->need_contacts_exception_);
bool can_pin_messages = user->can_pin_message_;
if (user_full->can_pin_messages != can_pin_messages) {
@ -10460,6 +10685,9 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
td_->messages_manager_->on_update_dialog_theme_name(DialogId(chat_id), std::move(chat->theme_emoticon_));
td_->messages_manager_->on_update_dialog_pending_join_requests(DialogId(chat_id), chat->requests_pending_,
std::move(chat->recent_requesters_));
auto bot_commands = get_bot_commands(std::move(chat->bot_info_), &chat_full->participants);
if (chat_full->bot_commands != bot_commands) {
chat_full->bot_commands = std::move(bot_commands);
@ -10503,6 +10731,9 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
td_->messages_manager_->on_update_dialog_theme_name(DialogId(channel_id), std::move(channel->theme_emoticon_));
td_->messages_manager_->on_update_dialog_pending_join_requests(DialogId(channel_id), channel->requests_pending_,
std::move(channel->recent_requesters_));
{
MessageTtlSetting message_ttl_setting;
if ((channel->flags_ & CHANNEL_FULL_FLAG_HAS_MESSAGE_TTL) != 0) {
@ -12557,8 +12788,10 @@ void ContactsManager::on_get_dialog_invite_link_info(const string &invite_link,
invite_link_info->dialog_id = DialogId();
invite_link_info->title = chat_invite->title_;
invite_link_info->photo = get_photo(td_->file_manager_.get(), std::move(chat_invite->photo_), DialogId());
invite_link_info->description = std::move(chat_invite->about_);
invite_link_info->participant_count = chat_invite->participants_count_;
invite_link_info->participant_user_ids = std::move(participant_user_ids);
invite_link_info->creates_join_request = std::move(chat_invite->request_needed_);
invite_link_info->is_chat = (chat_invite->flags_ & CHAT_INVITE_FLAG_IS_CHANNEL) == 0;
invite_link_info->is_channel = (chat_invite->flags_ & CHAT_INVITE_FLAG_IS_CHANNEL) != 0;
@ -12823,6 +13056,7 @@ void ContactsManager::on_update_chat_status(Chat *c, ChatId chat_id, DialogParti
bool need_drop_invite_link = c->status.can_manage_invite_links() && !status.can_manage_invite_links();
c->status = std::move(status);
c->is_status_changed = true;
if (c->status.is_left()) {
c->participant_count = 0;
@ -13416,14 +13650,10 @@ void ContactsManager::on_update_bot_stopped(UserId user_id, int32 date, bool is_
LOG(ERROR) << "Receive updateBotStopped by non-bot";
return;
}
if (!user_id.is_valid() || date <= 0) {
if (date <= 0 || !have_user_force(user_id)) {
LOG(ERROR) << "Receive invalid updateBotStopped by " << user_id << " at " << date;
return;
}
if (!have_user_force(user_id)) {
LOG(ERROR) << "Receive updateBotStopped by unknown " << user_id;
return;
}
DialogParticipant old_dialog_participant(DialogId(get_my_id()), user_id, date, DialogParticipantStatus::Banned(0));
DialogParticipant new_dialog_participant(DialogId(get_my_id()), user_id, date, DialogParticipantStatus::Member());
@ -13537,6 +13767,24 @@ void ContactsManager::on_update_channel_participant(ChannelId channel_id, UserId
new_dialog_participant);
}
void ContactsManager::on_update_chat_invite_requester(DialogId dialog_id, UserId user_id, string about, int32 date,
DialogInviteLink invite_link) {
if (!td_->auth_manager_->is_bot() || date <= 0 || !have_user_force(user_id) ||
!td_->messages_manager_->have_dialog_info_force(dialog_id)) {
LOG(ERROR) << "Receive invalid updateBotChatInviteRequester by " << user_id << " in " << dialog_id << " at "
<< date;
return;
}
td_->messages_manager_->force_create_dialog(dialog_id, "on_update_chat_invite_requester", true);
send_closure(G()->td(), &Td::send_update,
td_api::make_object<td_api::updateNewChatJoinRequest>(
dialog_id.get(),
td_api::make_object<td_api::chatJoinRequest>(
get_user_id_object(user_id, "on_update_chat_invite_requester"), date, about),
invite_link.get_chat_invite_link_object(this)));
}
void ContactsManager::update_contacts_hints(const User *u, UserId user_id, bool from_database) {
bool is_contact = is_user_contact(u, user_id, false);
if (td_->auth_manager_->is_bot()) {
@ -15994,8 +16242,7 @@ tl_object_ptr<td_api::secretChat> ContactsManager::get_secret_chat_object_const(
secret_chat->is_outbound, secret_chat->key_hash, secret_chat->layer);
}
tl_object_ptr<td_api::chatInviteLinkInfo> ContactsManager::get_chat_invite_link_info_object(
const string &invite_link) const {
tl_object_ptr<td_api::chatInviteLinkInfo> ContactsManager::get_chat_invite_link_info_object(const string &invite_link) {
auto it = invite_link_infos_.find(invite_link);
if (it == invite_link_infos_.end()) {
return nullptr;
@ -16008,8 +16255,10 @@ tl_object_ptr<td_api::chatInviteLinkInfo> ContactsManager::get_chat_invite_link_
string title;
const DialogPhoto *photo = nullptr;
DialogPhoto invite_link_photo;
string description;
int32 participant_count = 0;
vector<int64> member_user_ids;
bool creates_join_request = false;
bool is_public = false;
bool is_member = false;
td_api::object_ptr<td_api::ChatType> chat_type;
@ -16054,12 +16303,15 @@ tl_object_ptr<td_api::chatInviteLinkInfo> ContactsManager::get_chat_invite_link_
default:
UNREACHABLE();
}
description = get_dialog_about(dialog_id);
} else {
title = invite_link_info->title;
invite_link_photo = as_fake_dialog_photo(invite_link_info->photo, dialog_id);
photo = &invite_link_photo;
description = invite_link_info->description;
participant_count = invite_link_info->participant_count;
member_user_ids = get_user_ids_object(invite_link_info->participant_user_ids, "get_chat_invite_link_info_object");
creates_join_request = invite_link_info->creates_join_request;
is_public = invite_link_info->is_public;
if (invite_link_info->is_chat) {
@ -16082,7 +16334,8 @@ tl_object_ptr<td_api::chatInviteLinkInfo> ContactsManager::get_chat_invite_link_
return make_tl_object<td_api::chatInviteLinkInfo>(dialog_id.get(), accessible_for, std::move(chat_type), title,
get_chat_photo_info_object(td_->file_manager_.get(), photo),
participant_count, std::move(member_user_ids), is_public);
description, participant_count, std::move(member_user_ids),
creates_join_request, is_public);
}
UserId ContactsManager::get_support_user(Promise<Unit> &&promise) {

View File

@ -204,6 +204,8 @@ class ContactsManager final : public Actor {
void on_update_channel_participant(ChannelId channel_id, UserId user_id, int32 date, DialogInviteLink invite_link,
tl_object_ptr<telegram_api::ChannelParticipant> old_participant,
tl_object_ptr<telegram_api::ChannelParticipant> new_participant);
void on_update_chat_invite_requester(DialogId dialog_id, UserId user_id, string about, int32 date,
DialogInviteLink invite_link);
int32 on_update_peer_located(vector<tl_object_ptr<telegram_api::PeerLocated>> &&peers, bool from_update);
@ -319,6 +321,8 @@ class ContactsManager final : public Actor {
void set_location_visibility();
void get_is_location_visible(Promise<Unit> &&promise);
FileId get_profile_photo_file_id(int64 photo_id) const;
void set_profile_photo(const td_api::object_ptr<td_api::InputChatPhoto> &input_photo, Promise<Unit> &&promise);
@ -384,10 +388,12 @@ class ContactsManager final : public Actor {
void transfer_dialog_ownership(DialogId dialog_id, UserId user_id, const string &password, Promise<Unit> &&promise);
void export_dialog_invite_link(DialogId dialog_id, int32 expire_date, int32 usage_limit, bool is_permanent,
void export_dialog_invite_link(DialogId dialog_id, string title, int32 expire_date, int32 usage_limit,
bool creates_join_request, bool is_permanent,
Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise);
void edit_dialog_invite_link(DialogId dialog_id, const string &link, int32 expire_date, int32 usage_limit,
void edit_dialog_invite_link(DialogId dialog_id, const string &link, string title, int32 expire_date,
int32 usage_limit, bool creates_join_request,
Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise);
void get_dialog_invite_link(DialogId dialog_id, const string &invite_link,
@ -404,6 +410,12 @@ class ContactsManager final : public Actor {
td_api::object_ptr<td_api::chatInviteLinkMember> offset_member, int32 limit,
Promise<td_api::object_ptr<td_api::chatInviteLinkMembers>> &&promise);
void get_dialog_join_requests(DialogId dialog_id, const string &invite_link, const string &query,
td_api::object_ptr<td_api::chatJoinRequest> offset_request, int32 limit,
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 revoke_dialog_invite_link(DialogId dialog_id, const string &link,
Promise<td_api::object_ptr<td_api::chatInviteLinks>> &&promise);
@ -568,7 +580,7 @@ class ContactsManager final : public Actor {
tl_object_ptr<td_api::chatMember> get_chat_member_object(const DialogParticipant &dialog_participant) const;
tl_object_ptr<td_api::chatInviteLinkInfo> get_chat_invite_link_info_object(const string &invite_link) const;
tl_object_ptr<td_api::chatInviteLinkInfo> get_chat_invite_link_info_object(const string &invite_link);
UserId get_support_user(Promise<Unit> &&promise);
@ -728,6 +740,7 @@ class ContactsManager final : public Actor {
bool is_title_changed = true;
bool is_photo_changed = true;
bool is_default_permissions_changed = true;
bool is_status_changed = true;
bool is_is_active_changed = true;
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
@ -929,8 +942,10 @@ class ContactsManager final : public Actor {
// unknown dialog
string title;
Photo photo;
string description;
int32 participant_count = 0;
vector<UserId> participant_user_ids;
bool creates_join_request = false;
bool is_chat = false;
bool is_channel = false;
bool is_public = false;
@ -973,6 +988,7 @@ class ContactsManager final : public Actor {
static constexpr size_t MAX_NAME_LENGTH = 64; // server side limit for first/last name
static constexpr size_t MAX_DESCRIPTION_LENGTH = 255; // server side limit for chat/channel description
static constexpr size_t MAX_BIO_LENGTH = 70; // server side limit
static constexpr size_t MAX_INVITE_LINK_TITLE_LENGTH = 32; // server side limit
static constexpr int32 MAX_GET_CHANNEL_PARTICIPANTS = 200; // server side limit
static constexpr int32 CHANNEL_PARTICIPANT_CACHE_TIME = 1800; // some reasonable limit
@ -1028,6 +1044,7 @@ class ContactsManager final : public Actor {
static constexpr int32 CHAT_FULL_FLAG_HAS_FOLDER_ID = 1 << 11;
static constexpr int32 CHAT_FULL_FLAG_HAS_ACTIVE_GROUP_CALL = 1 << 12;
static constexpr int32 CHAT_FULL_FLAG_HAS_MESSAGE_TTL = 1 << 14;
static constexpr int32 CHAT_FULL_FLAG_HAS_PENDING_REQUEST_COUNT = 1 << 17;
static constexpr int32 CHANNEL_FLAG_USER_IS_CREATOR = 1 << 0;
static constexpr int32 CHANNEL_FLAG_USER_HAS_LEFT = 1 << 2;
@ -1078,6 +1095,7 @@ class ContactsManager final : public Actor {
static constexpr int32 CHANNEL_FULL_FLAG_IS_BLOCKED = 1 << 22;
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_PENDING_REQUEST_COUNT = 1 << 28;
static constexpr int32 CHAT_INVITE_FLAG_IS_CHANNEL = 1 << 0;
static constexpr int32 CHAT_INVITE_FLAG_IS_BROADCAST = 1 << 1;
@ -1383,11 +1401,14 @@ class ContactsManager final : public Actor {
void set_location_visibility_expire_date(int32 expire_date);
void on_get_is_location_visible(Result<tl_object_ptr<telegram_api::Updates>> &&result, Promise<Unit> &&promise);
void update_is_location_visible();
static bool is_channel_public(const Channel *c);
void export_dialog_invite_link_impl(DialogId dialog_id, int32 expire_date, int32 usage_limit, bool is_permanent,
void export_dialog_invite_link_impl(DialogId dialog_id, string title, int32 expire_date, int32 usage_limit,
bool creates_join_request, bool is_permanent,
Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise);
void remove_dialog_access_by_invite_link(DialogId dialog_id);

View File

@ -380,6 +380,7 @@ void CountryInfoManager::on_get_country_list(const string &language_code,
void CountryInfoManager::on_get_country_list_impl(const string &language_code,
tl_object_ptr<telegram_api::help_CountriesList> country_list) {
CHECK(country_list != nullptr);
LOG(DEBUG) << "Receive " << to_string(country_list);
auto &countries = countries_[language_code];
switch (country_list->get_id()) {
case telegram_api::help_countriesListNotModified::ID:
@ -395,6 +396,8 @@ void CountryInfoManager::on_get_country_list_impl(const string &language_code,
auto list = move_tl_object_as<telegram_api::help_countriesList>(country_list);
if (countries == nullptr) {
countries = make_unique<CountryList>();
} else {
countries->countries.clear();
}
for (auto &c : list->countries_) {
CountryInfo info;
@ -441,68 +444,70 @@ const CountryInfoManager::CountryList *CountryInfoManager::get_country_list(Coun
if (language_code == "en") {
static const BufferSlice en = gzdecode(
base64url_decode(
"eJyNW81uI0lyzhb13-qeaXs8uwdjQMDAehfwLMj6ryP_RZFFsVmk_m5JMofMUbFKU6ySVnqBve0jGAb2sNiDb_YTtH034LfYi1_"
"BUaTEKlYFsxrobqmpjMzIyIgvvohM_Wv4P3_8h__6z3_8GyHkn_70xy_whexV6uSo4k4936fRz97BZ__"
"334XqHnwtyLr29tnxzU1x9WdLtkG-G7k8YNNixafjYmPBfRqwJfwsM5epl98-e7-aaPX3Jp6rSd5XfprNqcuXAXXT8numTBLymwli-"
"Rb5VHEDPgtp8TfFKvXH4ZRm9dgvS5qR0O_"
"4TZGtfbXJccWdhdxxKLKXaA4ld44u2NUZw3YQu6qq2BYWyPoLhsrqyttnp7FsYt1Lcgi6e6B5RlZSFLENB-"
"Sk4s8YmNFN2W71c1VJrGOTj5UF8_mEukWbLrzsevtlzci30xD2Gi4DP7vXPSU-"
"89O15M32XkegbyRLHY6c9Z5WTvjMSj5l52tyUPHDMSJbkExdrPcdOa28MH9M-c_URfzdVIRnXK2Q76reEo4Y3PWc-"
"S9s5j2uzJ6dSzZ04ZlXq-Q48ng69bDYA39VtLxzqNbJaZW6M4dO2XKe1cEwSmIdGuSoypwZDxeZc5ClzXxnN29AksKSapOcVUP_"
"HkxQbNKlh9lBkrRtm67_xHO0wA6hM6M-T9uRrOPOjMeeg7507lOewRrAKvnts5Ob2FixbBtkQz90pzyro5o6q-"
"K2z1YvyEEVIttF92eKbWxFNvYXgGzZM1aUcu4Z98inKqjNeLFO_XC5pA5dIHpo8f7xeS5BD8_hjwg-qWZ5O2bT-_9Mfqh6LuU--"
"5eizd2g2IAIpgEPlxAINh3T7LmpZuLcBuSw6tMX7mTjXVU3n314XTh7dvbq3OmCLrE4kXJtOIT152GAxryuis_"
"vGvzTC5ZPFI9zScuJ89tVjEVHh-QFcU6p3oHezOEvDLFvqbwZV6uQwxroN90-hwJ8fVde6_"
"zbSEYpyQXV0Au6USoYklqQZA18v1TQSgr4j1TQdaMgwfeKXIb5tYJeMgtmCT43pCiOIReZBckwC7IiF2RNLShlDcbqBbVsFlTFKGhlua"
"ApMH9JLRglHWSjMQaMgb-wjlpWCqoOY41ywQAZQ4d5YB1Nhu9jO54l8tzWOdbq5FPNg0RZ_G2dLX5fHLCH3_"
"8OOxNFFtq11iTf1SBjQg4qVn5ap8NoLvR8ZTF-1Vrk7FWnV3UwfSSxPufkvf3EA0hNDnWn2ZyazImYfJt8rH35j4AVp__"
"cfvQgTDGcUrfjrJiNs1on2ot3X2wvIz3SeWnld5ohxeO75KA25w5D8riqifN4zSLHNQpkxPNc3O4bf0DxvNZbrZ3mPKu1DS2JKYnVk_"
"KXsL7neItxJu-s9dfT-Q_xxwE5rXmAhMUB-FB2DxBD4j2MyH5tRWWQ9dM8KoXJtStYmz6w4hXzp9h5y4YQE2uAa7XQp1_-QtN5-"
"90rfr999s5Myt0C1jw_AJwhnEfNObM78NMXNplH0RaOHT7JzqFIpYSvZ_luHThLC_IpdZ-zcWKu5tt_PbMN_YzmKmub_74v6_"
"H3slYqF5WyaSTXuCDH9Z_52AsDjvqmKgsxod4hR3XmLqh_"
"n9UxzneojeoQF3Vvwd3IozBeqGs6ycl39Uvy8W2OV2SLxhe25jFK5o55EmOkrxij7BoT63MX1VUzhtQLBaksp-"
"IsyzMbNXLUmIRAlX2Eu4ixvgH-0lgGHl6XScKzaLTIQWP2_BAg8SmVkviQhJiE_ADW9nngM2TfMec6iWlDQtYmB_YDxTjnnqyI6-"
"rGkBw3gjn3HlBsA_8V1_VN4MpN7qZzEVnHuBGPuyD7Tf4zGiOabgp9otkh3zapcx8tIso3aqkUy1jk1OIT33PZkiOcUzNjTtS8JB-"
"a1PdYPDlyBhuMPErbsAmctelTd5LF1j1ZTuSX4pbTbuRbFXLQomMPrRmUbb79KhzLVsnH1x5Nh7uzqbfI6qBs-"
"8AboMVz1AEnfRaRQqTu0OW8mG2tcNbzZ0jcmKYq9L9WE2wPawPQt0JOsb4ExK0Sjz8HW80z417zmDi-"
"W21y0uJjoHIB9bE6XC0JY7zVBXmfsZW3oz5i7vSRlkUOW3TFIBC-VRLbtweyIXcZKivu-bT65LQFcMgcL3xAcr9qbtbeiamtz-"
"RT45eQBh6gslN8VQXzVXE-bkGcRPZD42QLI3EO1RqC_UENtqAOtr5akrZiJc2DWsChQH6BYNB-WdNz6-"
"vWNfmw3vyPVQ7VdYjaQBXPcRud5XPkwIifx3z5vENOzqFWKHbgH2QdQxXv9bxHjkF-CrQN7deqJUXo6-eQj2q-"
"B4U7kgsNcR18PiQH55RHhAhZ1xSvOyJH56E7o36Ws8kaEfpXu05O2u70FfKRfmHcpzqNYTBeuw041vYZVlcBNoixpd0lh-"
"2lT1m2b1EwdXFN14b6BPRGdTbL29j9qnUse0nO6pxBTdmi_mRHDlc0oU-2P5P9tk9_wWRNTcmNy_ZgJY_VZnumkR_XbRvsPtlld0WsO_"
"haO6DOM8Z9TLG_XFjk6IIuKFDfLB4Yem5P9eKSHF54_hTtFWmJM0dq2os-"
"ObigDxTjbEY5aTOcL3Ya5KDD3GcUh1VxTui0yGnn2Z89vyzxPpepCeOkc76qx8feFPc3QxXjQ6dNjjvc52OK10yaIa6FO3BuNW_h-"
"V62TyZpYi7Z6ZG_t2nUl-zwIIh6kj32yJFeoaHl1iqdPnnf8_xgDiCd4u1kbYeYj3YG5L0NRSIydn3mUtJXN2cey1-Tw074BKiK-"
"Zoqttct1NL0GergDcHN7leGajNvv3fgN_SF3s8zfrPqH-pr-Wi-d1r8_zX33TjCNvftVsh-l6L3GmA_"
"LSFfTLhSQr5KjrpsTF0P6fNrZaEfdmtwJitf6IaTbJ6D-lnNvUvstsmHLmeTecDcZcDQvr8iifvtXcj1ts-"
"LXereozlASfvGNpZ0IVd3-RivmWVx_da1I_stvWDuIbGkie0HfKzLg3kY3YJifFrf4tNrHEnue0ROu-"
"EfGCBJ6M8wPp7Mm1kc616Rwy4NHjFOLetl8dq35ABshuNn2RDazKqQIwvQZzJBbFYW53qrRg4tz6UTD9NZ3BOz6tG6ztR7xPoTsvCsrA"
"bUw54LXspm_vbaK6ySE71aC_KDBcXgjC4nUCghfrGx7VkyLpM-bZ2Tby3qL-fUcYQ94gTntTrkmzWeWnTCpngfxhDfoVldsm9RB-_"
"FSeJ7PwvyigXUfEH9tJ57ppoYB9zaivr4Dp7_TD0VNylubl2SA9ghWj8Yao6OffLrlY2Y74KZ_Khk3mHft7qmlIdh1ufovP2Au_"
"yXELs_MrV47CAaG_o8WAU9YmNxn8yy1364ZL5Ps7kM9M1_e2ENI_tBEY_W8OI7GGtETtb68xDt88jiHoB1BWdPnSl_"
"3PEORhPX8hbkcZCnTxyLK_Edn3UDsuwPfJKN3z1VSqxxu9KRPi_x-wrtK_"
"qR1l10Ti9RxyLtE68cU4yRPcDIHl3wMZaTNPHbiV6NfOixp2KNOmsUQO-"
"W9Hg8cOEenzGspyNJutAfek3yEeLpJ895u8pC1tJjjOq1YF98R39aVnLt2muTkx4UHD6dhZj_qiUxl-t1gXOyKPxXIZ-"
"tecobDpbuN34w9VinrTmhjgEbPNFnpHcY323h-kAd02MP1EFxUM-3xwDkIR5D7Iz1uO_"
"XG5H9HgdPRH1BjsfdRfZ5Kt4xit6Paop4P5cW2b9coLUsxLYhlO1XyGEf8HiB3u-Jc3u_Qfb7LDIDcr-33QPI8KB-k3z72kPte87za_"
"sDs1P8zqLfIt_26UNIi5G13lp62Bmoscw5ed-fc4c_PMDwrO9pchJX8Fq_3yHHfXq_egSI7dXMvCVC5uiCnb1MrK791cixlUV-"
"teb8fQ4piEEBaEUI52zXD2R9ZvH9RR_qt37I_MCLLnC9txhL1ArGrru2eIwp59aUfZuc9AH3lpCNkbtyiKl0j3UbO_tDsC_"
"wg3AWhSSWH8ti-1yTA1g_zU1e_SeuZ_u30TmuUOwZW0fN6ft_rpCDzxTvw5s5byAHDXI8-PLX0OU73gNo4rphcEmOBt4Ce7u5p5TE_"
"jOwyaHNfLSPLxviWmswIn83CJcQnW6xyaYMCFC0g_Q8ybp5ZwwMgEcMniAEMA6mpn1kew92hZzZNJzy1bPeHRxW04R7savkGzt6E-"
"FtmgoIdsQ52q6RU5s9T-bMAefGepRGfOZx0orl6-"
"TADqdYvyx6ayTWtQFn9gQGz9p6T9nqKSOyLajNuTujD56PvV3Rcu7o7fPI1hHenDOHbd6F7SXtJCl64g5pc3aHab-32-"
"TYdrxH5uJnJhviet3urOUBflF5RRJjg92FvUSoSYtd5rnpXPzKgSSxDhb4AV2XLi5aAxu5vm_3yJEdFbLUQfieOAZtiH0bYt_B-Juao_"
"sA7AelA2R4dO9qzpti237rAa48Gekd5Og-JN_bX_7sFYfe4stfIXP1_S__7k44dq8nyck-6BvlS-"
"hyRd43nKJNnUf8rURJXIfaN5EvgFtbFCpHhuEw5ESpTHLynX0Lcf3so_0jU5PF_nhHjhvLJxoVrqgv5vC1YY18Pwz9-6gLXKOQ1ZeC_"
"qiW_3ZlWCf7tTmd4nGRqu1SdciwRfaH3mzHu2hD6JfDc3I8nFO-vpZGMCrnfd3wgpwO6c_"
"8lZVlz8EU97SGHXI09O4ZsIZsDjBjzjCE2mXIF57_Yxf4DUPyRWKsRc6is4l-S2IHVwS9kj669vGt8wWcGAJLWKJvicRYObwkB0MPcB_"
"lxHE_ZDggh5GeDKmdzK-40x4OyachQAqf0im44dAb08gJsv5n5P9ey_Aq0uWROiHG3WIuOwTuMKT8CTtrw9CEMTeEmBtS94XuyEFSzu-"
"-jCrkaHQfPctnGVk5_h2Es41sqq84apHD0WwX7xFzlpFNCiO7kuFb5a_gW6Nb0NsPI7qL4P42d0n3-"
"0Z35HT0Mma748vI3fdVjfyw5hFX3J0w-PqbYjBnxfW7nagcw_A3__"
"dzrhrk5Apy6QuUQAgG76lfcX971SLfV6OO2nIO2vkzLrpnkr5Cpzb5NLLTU6F3VqXcuQADrjgLIGenY2LPSPy-"
"09UIxlE3pAGCYXocO9dN8s01dRweJY1mGIRu9t5PM-K3ZdfR27zVr09hMbmqraPP9m5a5IeWA9HvFC1vzB0GqTkArswD-"
"O4Z0HKRlTcS69x0yGHHW3qPGKcyduby9dpX5Pu2GzDfXRUkoEKPBU8eJMYsVzUMKfF93He5bZCDW7ZgGD83NX0XpqzWv4V6_vbHTD2_-"
"pkixXeKyro22qx5F9UxKz61fpmP4NGepBMhJtxZ5PBu17usuJeLy16T4zu-GNPxE86FNfTNyJ__99_-9v8o_old")
"eJyNW0tz48iRrhb1lrpn2h6PfXBMMGIjvN6IHQeJN458iyJBsQlSr1uRrCFrBAIaEJAs_QHf9ifsxQeHD77t_oK27_"
"4Pvvmyl73sbROkSIBEstAR3S01VVmVlZX55ZdZpf8M__6HX_z1v3_9T0LIv_zHHz7DF7JXqpKjkjv2fJ9GP3sHn_"
"3P33LlPfiak3Vt9dnx7W1-8WdDtka-Gbg8YON8yafDfG3GfRqwOfwsNZepF1efnS0mWvy9jeeqk7PSD5Mpdfk8oO62_"
"J4pk4T8eoJYvkE-ltyAT0Ka_02-TP1hOKZpPfaLkmYk9DteKbKxryY5LrmTkDsORfYSzaFkztEGuzpD2A5iV1UV28ICWX_"
"GUFldWX12Gssm1r0ih6C7B5qnZCVFEduwR05K_oSBGd0t2y1-riqJdWzyoTRjPh9RN2_TmZdeb7-oGdl26sNew3ngp_"
"e6p8RnfrqS3djrAPSNZKnDkbPe04oJn1lIb9n5hhyU_HCIyOYkUxfrfU9OS6_MH1L-I3URfzcV4RmXS-SbsjeHIwZ3vWD-K5t4Twuzp-"
"eSDV145uUyOY48no49LPbAXxUt6xzKVXJapu7EoWM2n6Z1MIyCWIcaOSozZ8LDWeocZGk93_ntCki2sKRcJ-fl0H8AE-"
"TrdO5hdpAkbdOmyz_xHA2wQ-hMqM-37UiWcWfGYy9AXzr1KU9hDWCVvPrs5DY2VizbBNnQD90xT-"
"uobp1VftNny5fkoAyR7aL7M8U2tiIb-zNAtvQZK0ox84w75GMZ1GY8X6V-OJ9Th84QPbR4__g8V6CH5_"
"AnBJ9UsxjvYe32CdlP5Luy51Lus3_P29wN8jWIYBrwcA6BYNMhTZ-baibOrUcOyz595U463lV1_dn7FVykzs5enDud0TkWJ1KmDfuw_"
"jQM0JjXVfH53YB_esH8meJxLmkZcX63iLHo6JC8IM4p5XvQmzn8lSH2LRTX4yolclgB_cab55CDr--KS51_"
"G8koBTmnGnpONwo5Q1JzkqyB7xdyWkEB_"
"5Fyum7kJPhekYswv5bTC2bOLMDnhhTFMeQiMycZZk5W5JysqTmlqMFYPacWzZyqGDmtKOc0BeYvqDmjoINsNMaAMfAX1lGLSk7VYaxRz"
"BkgY-gwD6yjyfB9bMfzRJ7bOMdKlXyseJAo87-tstnv8j32-Lt_w85EkYV2rdTJNxXImJCD8qUflukwmgs9X1mMX5UGOX_"
"T6U0dTB9JrM8FObOfeQCpyaHuOJ1TkzkRk2-SD5XP_xWw_Phfm08ehCmGU-pmnOXTcVZpRXvxHvLNeaTHdl5a-"
"J1mSPH4NjmoTLnDkDyuauI8XrHIcYUCGfE8F7f72h9QPK90Fmtvc57F2oaWxJTE6kn5K1jfc7zZMJV3lvrr2_"
"kP8cceOa14gIT5HvhQeg8QQ-I9DMh-ZUFlkPWTPArB5Mo1rE0fWf6a-"
"WPsvGVDiIkVwLVK6NPPf6LbefvdG36vPntnJuXuAGteHgHOEM6jZpzZPfjpKxtNo2gLhw4fpedQpELC19N8twqcpQH5lLov6TgxF_"
"Ptv53ZinxG-z4rauv_nhX1-HtZKxTzStE0kmtckuPqj3zohQFHfVOVhZhQbZGjKnNn1H9I6xjnO9RGVYiLqjfjbuRRGC_"
"UNZ1k5LvqFfmwmuMN2aLxuY15jIK5Y57EGOkLxii7xsT63Ed11YQh9UJOKspbcZbmmbUKOaqNQqDKPsJdxFhfA3-"
"pzQMPr8sk4VnUGuSgNnl5DJD4lApJfEhCTEK-B2v7PPAZsu-Yc53EtCEha5MD-5FinHNPVsR1da1PjmvBlHuPKLaB_4rr-"
"jpw5Tp3t3MRWca4EY-7JPt1_iMaI5puCn2i3iJf16nzEC0iyjdqoRDLWOTU4iPfc9mcI5xTM2NOVL8i7-"
"vU91g8OXIGa4w82rZhHThr3afuKI2te7KcyC_"
"5DaddyzdK5KBBhx5aMyibfPtNOJYtkw9vPZoWdydjb5bWQdn0gRWgxXNUASd9FpFCpO7Q5ayYbSxw1vMnSNyYpir0v0YdbA9rA9A3Qk6"
"xvgTErRKPvwBbTVPj3vKYOL4bTXLS4EOgcgH1sTpcLQhjvNEGeZ-xhbejPmLu9JGGRQ4bdMEgEL5VENu3A7IhdxkqK-"
"75NLrktAFwyBwvfERyv2qu196JqY1P5GPtp5AGHqCyk39TBfNVcT5uQJxE9kPjZAMjcQ7V6IP9QQ02ow62vlqQNmJlmwc1gEOB_"
"AzBoP2ipmfW140b8n65-e_LHKrrELWBKp7jLjrLl8iBET-P-fJFi5xcQK2Qb8E_yDqGKt7rRYccg_"
"wYaBvar1ULitDXLyAfVXwPCnckFxriOviiTw4uKI8IEbKuKV53QI4uQndC_"
"TRnkzUi9K9mlZw03fEb5CP9wrhPhfYbm4BjTZ9hdRVggxhbmm1y2Jz7lKX7FjlTF9d0TahPQG9UZ7O4id1vWseyV-"
"S8yhnUlA3qj3bkcEUT-mTzE9lv-vQnTNbUlMy4bPYW8lhttmca2XHdtMHuo112V8S6g681A-q8YNzHFPvLpUWOLumMAvVN44GhZ_"
"ZUL6_I4aXnj9FekZY4c6SmveySg0v6SDHOZhSTNsP5YqtGDlrMfUFxWBXnhFaDnLZe_MnL6xzvc5maME5aF4t6fOiNcX8zVDE-"
"tJrkuMV9PqR4zaQZ4lq4BedW8Wae76X7ZJIm5pKtDvm5TaO-"
"ZIsHQdST7LAnjvQKDS2zVml1yVnH84MpgPQWbydLO8R8tNUjZzYUicjY5ZlLSV9dn3ksf0MOW-"
"EzoCrma6rYXndQS9MXqIPXBDe9Xxmqzaz93oPf0Ff6ME35zaJ_qC_lo_neafH_l9x37Qib3LddIvttit5rgP20hHw-4UoJ-"
"TI5arMhdT2kz68VhX7YrsCZLHyhHY7SeQ7qZzXzLrHdJO_bnI2mAXPnAUP7_ook7re3IdfbPs-"
"3qfuA5gBl2zc2saQNubrNh3jNLIvrt7Yd2W_uBVMPiSVNbD_gY20eTMPoFhTj0_oGn17iSHLfA3LaDn_PAElCf4Lx8WTeTONY-"
"5octmnwhHFqWS-K174jB2AzHD-LhtBmVokcWYA-oxFis6I411sVcmh5Lh15mM7inphVjdZ1xt4T1p-"
"QhWdl1aAe9lzwUjbxN9deYJWc6NVakB8sKAYndD6CQgnxi7Vtz5NxmfRp64J8bVF_PqWOI-"
"wRJziv1SJfLfHUoiM2xvswhvgOzWqTfYs6eC9OEt_7WZBXLKDmM-pv67lnqolxwK2tqI_v4PnP1LfiZoubW1fkAHaI1g-GmqFjl_"
"xqYSPmu2AmPyqZd9h3VdcUsjDM-hSdtx9wl_8UYvdHphaP7UVjQ58Hi6BHbCzuk1n20g_nzPdpOpeBvtlvL6x-"
"ZD8o4tEaXnwHYw3IyVJ_HqJ9HlncA7Cu4eypM-ZPO97BaOJa3oI8DvL0mWNxJb7js25Blv2ej9Lxu6dKiTXuFjrSlzl-X6F9QT_Suo_"
"O6TXqWGz7xBvHFGNkBzCyQ2d8iOUkTfx2olMh7zvsOV-hzhIF0LslPR4PXLjDJwzr6UiSLvSHTp18gHj6wXNWV1nIWnqMUZ0G7Ivv6E_"
"LSqZdO01y0oGCw6eTEPNftSDmcp02cE4Whf8i5NM1T3HNwbb7je9NPdZpY06oY8AGz_"
"QF6R3Gd1u4PlDHdNgjdVAc1LPt0QN5iMcQO2M97vt1BmS_w8ETUV-Q43H3kX2e8_"
"eMovejmiLez5VF9q9maC0LsW0IZbslctgFPJ6h93vi3N6tkf0ui8yA3O9t9gBSPKhbJ1-_9VC7nvPy1v7A7BS_s-g2yNdd-"
"hjSfGStVUsPOwM1lrkgZ90pd_jjIwxP-54mJ3EFr_W7LXLcpQ-"
"LR4DYXs3UWyJkjjbY2UvF6tJfjQxbWeSXS87f5ZCCGBSAVoRwzmb9QJZnFt9fdKF-"
"64bMD7zoAtdbxViiVjB23bXFY0w5s6bs2uSkC7g3h2yM3JVDTG33WDexs9sH-wI_CCdRSGL5sSi2zw05gPW3ucmb_"
"8T1bPcuOscFir1g66gZff9PJXLwieJ9eDPjDWSvRo57n_8cunzHewBNXDf0rshRz5thbzf3lILYf3o2ObSZj_bxZUNcb_"
"YG5Ge9cA7R6ebrbMyAAEU72J4nWTfvjIEe8IjeM4QAxsHUbR_Z3INdIuc2Dcd88ax3B4fVtnjUlp_"
"ZZfKVHb2J8NZNBQQ74hxtV8ipzV5GU-"
"aAc2M9SiO2XZy0YvkqObDDMdYvi94aiXWtwZk9g8HTtt5TNnrKiGwDanPuTuij52NvV7SMO3r7IrJ1hDcXzGHrd2F7STtJip64Q1qf3e"
"G2_9hNcmw73hNz8TOTDXG9breW8gC_qLwiibHBbsNeItSk-Tbz3O1c_MaBJLEOFvgBXZYuLloDG5m-b3fIkR0VstRB-J6432FD7NsQ-"
"w7G39QM3XtgPygdIMOje1cz3hTb9qoHuPBkpHeQoXuffGt__qOX73uzz3-GzNX1P__FHXHsXk-Sk33QFeVL6HJNzmpO3qbOE_"
"5WoiCuQ-3byBfArS0KlSPDcBhyolQkGfnOvoO4fvHR_pGpyWJ_vCfHtfkzjQpX1Bcz-Fq_Qr7th_5D1AWuUMjqc0F_VMt-"
"u9Kvkv3KlI7xuNiq7bbqkH6D7Pe9yY530YbQL_sX5Lg_pXx5LY1gVMb7uv4lOe3TH_kbK0ufgynuafVb5KjvPTBgDekcYMacoQ-1S5_"
"PPP_7NvAbhuSLxFiLnEdnE_2WxA6uCHolfXTp4xvnCzjRB5YwR98SibGyf0UO-h7gPsqJ435Iv0cOIz0ZUjuZX3Cn3e-"
"Tj32AFD6mY3DDvjekkROk_c_I_r2W_nWkyxN1Qoy7xVy2D9yhT_"
"kzdtaGoQljrg8x16fuK92Rg6SM330ZlMjR4CF6ls9SsnL8Owjna9mtvuKgQQ4Hk128R8xZBjbJDexSim8Vv4BvDe5Abz-M6C6C-"
"5vcZbvfN7gnp4PXIdsdX0bmvq8r5Lslj7jm7ojB19_kgynLL9_tROUYhr_Zv59zXSMn15BLX6EEQjB4T_2C-"
"9vrBvm2HHXU5lPQzp9w0T2T9AU6NcnHgb09FXpnVcicCzDgmrMAcvZ2TOwZid93uh7AOOqGNEAwTI9j56ZOvrqhjsOjpFEPg9BN3_"
"tpRvy27CZ6m7f49SksJhe1dfTZ3m2DfNdwIPqdvOUNucMgNQfAlXkA370AWs7S8kZindsWOWx5c-8J41TGzly-XPuafNt0A-"
"a7i4IEVOiw4NmDxJjmqoYhJb6P-y53NXJwx2YM4-empu_ClMX6d1DP332fqucXP1Ok-E5RWdZG6zXvozpmwaeWL_"
"MRPNqTdCLEhHuLHN7vepcV93Jx2RtyfM9nQzp8xrmwhr4Z-cf__p_7_0VkiUI")
.ok());
TlBufferParser parser(&en);
auto result = telegram_api::help_getCountriesList::fetch_result(parser);

View File

@ -6,11 +6,10 @@
//
#pragma once
#include "td/telegram/telegram_api.h"
#include "td/telegram/ChannelId.h"
#include "td/telegram/ChatId.h"
#include "td/telegram/SecretChatId.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/UserId.h"
#include "td/utils/common.h"

View File

@ -19,53 +19,61 @@ DialogInviteLink::DialogInviteLink(tl_object_ptr<telegram_api::chatInviteExporte
}
invite_link_ = std::move(exported_invite->link_);
LOG_IF(ERROR, !is_valid_invite_link(invite_link_)) << "Unsupported invite link " << invite_link_;
title_ = std::move(exported_invite->title_);
creator_user_id_ = UserId(exported_invite->admin_id_);
date_ = exported_invite->date_;
expire_date_ = exported_invite->expire_date_;
usage_limit_ = exported_invite->usage_limit_;
usage_count_ = exported_invite->usage_;
edit_date_ = exported_invite->start_date_;
request_count_ = exported_invite->requested_;
creates_join_request_ = exported_invite->request_needed_;
is_revoked_ = exported_invite->revoked_;
is_permanent_ = exported_invite->permanent_;
LOG_IF(ERROR, !is_valid_invite_link(invite_link_)) << "Unsupported invite link " << invite_link_;
if (!creator_user_id_.is_valid()) {
LOG(ERROR) << "Receive invalid " << creator_user_id_ << " as creator of a link " << invite_link_;
creator_user_id_ = UserId();
}
date_ = exported_invite->date_;
if (date_ < 1000000000) {
if (date_ != 0 && date_ < 1000000000) {
LOG(ERROR) << "Receive wrong date " << date_ << " as a creation date of a link " << invite_link_;
date_ = 0;
}
if ((exported_invite->flags_ & telegram_api::chatInviteExported::EXPIRE_DATE_MASK) != 0) {
expire_date_ = exported_invite->expire_date_;
if (expire_date_ < 1000000000) {
LOG(ERROR) << "Receive wrong date " << expire_date_ << " as an expire date of a link " << invite_link_;
expire_date_ = 0;
}
if (expire_date_ != 0 && expire_date_ < 1000000000) {
LOG(ERROR) << "Receive wrong date " << expire_date_ << " as an expire date of a link " << invite_link_;
expire_date_ = 0;
}
if ((exported_invite->flags_ & telegram_api::chatInviteExported::USAGE_LIMIT_MASK) != 0) {
usage_limit_ = exported_invite->usage_limit_;
if (usage_limit_ < 0) {
LOG(ERROR) << "Receive wrong usage limit " << usage_limit_ << " for a link " << invite_link_;
usage_limit_ = 0;
}
if (usage_limit_ < 0) {
LOG(ERROR) << "Receive wrong usage limit " << usage_limit_ << " for a link " << invite_link_;
usage_limit_ = 0;
}
if ((exported_invite->flags_ & telegram_api::chatInviteExported::USAGE_MASK) != 0) {
usage_count_ = exported_invite->usage_;
if (usage_count_ < 0) {
LOG(ERROR) << "Receive wrong usage count " << usage_count_ << " for a link " << invite_link_;
usage_count_ = 0;
}
if (usage_count_ < 0) {
LOG(ERROR) << "Receive wrong usage count " << usage_count_ << " for a link " << invite_link_;
usage_count_ = 0;
}
if ((exported_invite->flags_ & telegram_api::chatInviteExported::START_DATE_MASK) != 0) {
edit_date_ = exported_invite->start_date_;
if (edit_date_ < 1000000000) {
LOG(ERROR) << "Receive wrong date " << edit_date_ << " as an edit date of a link " << invite_link_;
edit_date_ = 0;
}
if (edit_date_ != 0 && edit_date_ < 1000000000) {
LOG(ERROR) << "Receive wrong date " << edit_date_ << " as an edit date of a link " << invite_link_;
edit_date_ = 0;
}
if (request_count_ < 0) {
LOG(ERROR) << "Receive wrong pending join request count " << request_count_ << " for a link " << invite_link_;
request_count_ = 0;
}
is_revoked_ = exported_invite->revoked_;
is_permanent_ = exported_invite->permanent_;
if (is_permanent_ && (usage_limit_ > 0 || expire_date_ > 0 || edit_date_ > 0)) {
if (is_permanent_ && (!title_.empty() || expire_date_ > 0 || usage_limit_ > 0 || edit_date_ > 0 ||
request_count_ > 0 || creates_join_request_)) {
LOG(ERROR) << "Receive wrong permanent " << *this;
title_.clear();
expire_date_ = 0;
usage_limit_ = 0;
edit_date_ = 0;
request_count_ = 0;
creates_join_request_ = false;
}
if (creates_join_request_ && usage_limit_ > 0) {
LOG(ERROR) << "Receive wrong permanent " << *this;
usage_limit_ = 0;
}
}
@ -81,15 +89,18 @@ td_api::object_ptr<td_api::chatInviteLink> DialogInviteLink::get_chat_invite_lin
}
return td_api::make_object<td_api::chatInviteLink>(
invite_link_, contacts_manager->get_user_id_object(creator_user_id_, "get_chat_invite_link_object"), date_,
edit_date_, expire_date_, usage_limit_, usage_count_, is_permanent_, is_revoked_);
invite_link_, title_, contacts_manager->get_user_id_object(creator_user_id_, "get_chat_invite_link_object"),
date_, edit_date_, expire_date_, usage_limit_, usage_count_, request_count_, creates_join_request_, is_permanent_,
is_revoked_);
}
bool operator==(const DialogInviteLink &lhs, const DialogInviteLink &rhs) {
return lhs.invite_link_ == rhs.invite_link_ && lhs.creator_user_id_ == rhs.creator_user_id_ &&
lhs.date_ == rhs.date_ && lhs.edit_date_ == rhs.edit_date_ && lhs.expire_date_ == rhs.expire_date_ &&
lhs.usage_limit_ == rhs.usage_limit_ && lhs.usage_count_ == rhs.usage_count_ &&
lhs.is_permanent_ == rhs.is_permanent_ && lhs.is_revoked_ == rhs.is_revoked_;
return lhs.invite_link_ == rhs.invite_link_ && lhs.title_ == rhs.title_ &&
lhs.creator_user_id_ == rhs.creator_user_id_ && lhs.date_ == rhs.date_ && lhs.edit_date_ == rhs.edit_date_ &&
lhs.expire_date_ == rhs.expire_date_ && lhs.usage_limit_ == rhs.usage_limit_ &&
lhs.usage_count_ == rhs.usage_count_ && lhs.request_count_ == rhs.request_count_ &&
lhs.creates_join_request_ == rhs.creates_join_request_ && lhs.is_permanent_ == rhs.is_permanent_ &&
lhs.is_revoked_ == rhs.is_revoked_;
}
bool operator!=(const DialogInviteLink &lhs, const DialogInviteLink &rhs) {
@ -97,10 +108,12 @@ bool operator!=(const DialogInviteLink &lhs, const DialogInviteLink &rhs) {
}
StringBuilder &operator<<(StringBuilder &string_builder, const DialogInviteLink &invite_link) {
return string_builder << "ChatInviteLink[" << invite_link.invite_link_ << " by " << invite_link.creator_user_id_
<< " created at " << invite_link.date_ << " edited at " << invite_link.edit_date_
<< " expiring at " << invite_link.expire_date_ << " used by " << invite_link.usage_count_
<< " with usage limit " << invite_link.usage_limit_ << "]";
return string_builder << "ChatInviteLink[" << invite_link.invite_link_ << '(' << invite_link.title_ << ')'
<< (invite_link.creates_join_request_ ? " creating join request" : "") << " by "
<< invite_link.creator_user_id_ << " created at " << invite_link.date_ << " edited at "
<< invite_link.edit_date_ << " expiring at " << invite_link.expire_date_ << " used by "
<< invite_link.usage_count_ << " with usage limit " << invite_link.usage_limit_ << " and "
<< invite_link.request_count_ << "pending join requests]";
}
} // namespace td

View File

@ -21,12 +21,15 @@ class ContactsManager;
class DialogInviteLink {
string invite_link_;
string title_;
UserId creator_user_id_;
int32 date_ = 0;
int32 edit_date_ = 0;
int32 expire_date_ = 0;
int32 usage_limit_ = 0;
int32 usage_count_ = 0;
int32 request_count_ = 0;
bool creates_join_request_ = false;
bool is_revoked_ = false;
bool is_permanent_ = false;
@ -66,6 +69,8 @@ class DialogInviteLink {
bool has_usage_limit = usage_limit_ != 0;
bool has_usage_count = usage_count_ != 0;
bool has_edit_date = edit_date_ != 0;
bool has_request_count = request_count_ != 0;
bool has_title = !title_.empty();
BEGIN_STORE_FLAGS();
STORE_FLAG(is_revoked_);
STORE_FLAG(is_permanent_);
@ -73,6 +78,9 @@ class DialogInviteLink {
STORE_FLAG(has_usage_limit);
STORE_FLAG(has_usage_count);
STORE_FLAG(has_edit_date);
STORE_FLAG(has_request_count);
STORE_FLAG(creates_join_request_);
STORE_FLAG(has_title);
END_STORE_FLAGS();
store(invite_link_, storer);
store(creator_user_id_, storer);
@ -89,6 +97,12 @@ class DialogInviteLink {
if (has_edit_date) {
store(edit_date_, storer);
}
if (has_request_count) {
store(request_count_, storer);
}
if (has_title) {
store(title_, storer);
}
}
template <class ParserT>
@ -98,6 +112,8 @@ class DialogInviteLink {
bool has_usage_limit;
bool has_usage_count;
bool has_edit_date;
bool has_request_count;
bool has_title;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(is_revoked_);
PARSE_FLAG(is_permanent_);
@ -105,6 +121,9 @@ class DialogInviteLink {
PARSE_FLAG(has_usage_limit);
PARSE_FLAG(has_usage_count);
PARSE_FLAG(has_edit_date);
PARSE_FLAG(has_request_count);
PARSE_FLAG(creates_join_request_);
PARSE_FLAG(has_title);
END_PARSE_FLAGS();
parse(invite_link_, parser);
parse(creator_user_id_, parser);
@ -121,6 +140,15 @@ class DialogInviteLink {
if (has_edit_date) {
parse(edit_date_, parser);
}
if (has_request_count) {
parse(request_count_, parser);
}
if (has_title) {
parse(title_, parser);
}
if (creates_join_request_) {
usage_limit_ = 0;
}
}
};

View File

@ -422,7 +422,7 @@ DialogParticipantStatus get_dialog_participant_status(const tl_object_ptr<td_api
return DialogParticipantStatus::Administrator(
st->is_anonymous_, custom_title, true /*st->can_be_edited_*/, st->can_manage_chat_, st->can_change_info_,
st->can_post_messages_, st->can_edit_messages_, st->can_delete_messages_, st->can_invite_users_,
st->can_restrict_members_, st->can_pin_messages_, st->can_promote_members_, st->can_manage_voice_chats_);
st->can_restrict_members_, st->can_pin_messages_, st->can_promote_members_, st->can_manage_video_chats_);
}
case td_api::chatMemberStatusMember::ID:
return DialogParticipantStatus::Member();
@ -711,16 +711,15 @@ DialogParticipant::DialogParticipant(tl_object_ptr<telegram_api::ChannelParticip
}
case telegram_api::channelParticipantCreator::ID: {
auto participant = move_tl_object_as<telegram_api::channelParticipantCreator>(participant_ptr);
bool is_anonymous = (participant->admin_rights_->flags_ & telegram_api::chatAdminRights::ANONYMOUS_MASK) != 0;
*this = {DialogId(UserId(participant->user_id_)), UserId(), 0,
DialogParticipantStatus::Creator(true, is_anonymous, std::move(participant->rank_))};
DialogParticipantStatus::Creator(true, participant->admin_rights_->anonymous_,
std::move(participant->rank_))};
break;
}
case telegram_api::channelParticipantAdmin::ID: {
auto participant = move_tl_object_as<telegram_api::channelParticipantAdmin>(participant_ptr);
bool can_be_edited = (participant->flags_ & telegram_api::channelParticipantAdmin::CAN_EDIT_MASK) != 0;
*this = {DialogId(UserId(participant->user_id_)), UserId(participant->promoted_by_), participant->date_,
get_dialog_participant_status(can_be_edited, std::move(participant->admin_rights_),
get_dialog_participant_status(participant->can_edit_, std::move(participant->admin_rights_),
std::move(participant->rank_))};
break;
}
@ -731,9 +730,8 @@ DialogParticipant::DialogParticipant(tl_object_ptr<telegram_api::ChannelParticip
}
case telegram_api::channelParticipantBanned::ID: {
auto participant = move_tl_object_as<telegram_api::channelParticipantBanned>(participant_ptr);
auto is_member = (participant->flags_ & telegram_api::channelParticipantBanned::LEFT_MASK) == 0;
*this = {DialogId(participant->peer_), UserId(participant->kicked_by_), participant->date_,
get_dialog_participant_status(is_member, std::move(participant->banned_rights_))};
get_dialog_participant_status(!participant->left_, std::move(participant->banned_rights_))};
break;
}
default:

View File

@ -17,6 +17,7 @@
#include "td/telegram/misc.h"
#include "td/telegram/net/DcId.h"
#include "td/telegram/Photo.h"
#include "td/telegram/PhotoSizeSource.h"
#include "td/telegram/secret_api.h"
#include "td/telegram/StickersManager.h"
#include "td/telegram/Td.h"
@ -270,9 +271,9 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
if (document_type != Document::Type::VoiceNote) {
for (auto &thumb : document->thumbs_) {
auto photo_size =
get_photo_size(td_->file_manager_.get(), {FileType::Thumbnail, 0}, id, access_hash, file_reference,
DcId::create(dc_id), owner_dialog_id, std::move(thumb), thumbnail_format);
auto photo_size = get_photo_size(td_->file_manager_.get(), PhotoSizeSource::thumbnail(FileType::Thumbnail, 0),
id, access_hash, file_reference, DcId::create(dc_id), owner_dialog_id,
std::move(thumb), thumbnail_format);
if (photo_size.get_offset() == 0) {
if (!thumbnail.file_id.is_valid()) {
thumbnail = std::move(photo_size.get<0>());
@ -284,8 +285,9 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
}
for (auto &thumb : document->video_thumbs_) {
if (thumb->type_ == "v") {
animated_thumbnail = get_animation_size(td_->file_manager_.get(), {FileType::Thumbnail, 0}, id, access_hash,
file_reference, DcId::create(dc_id), owner_dialog_id, std::move(thumb));
animated_thumbnail =
get_animation_size(td_->file_manager_.get(), PhotoSizeSource::thumbnail(FileType::Thumbnail, 0), id,
access_hash, file_reference, DcId::create(dc_id), owner_dialog_id, std::move(thumb));
if (animated_thumbnail.file_id.is_valid()) {
break;
}

View File

@ -6,16 +6,15 @@
//
#pragma once
#include "td/telegram/secret_api.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/DialogId.h"
#include "td/telegram/Document.h"
#include "td/telegram/EncryptedFile.h"
#include "td/telegram/files/FileId.h"
#include "td/telegram/Photo.h"
#include "td/telegram/secret_api.h"
#include "td/telegram/SecretInputMedia.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/buffer.h"
#include "td/utils/common.h"

View File

@ -55,7 +55,7 @@ unique_ptr<DraftMessage> get_draft_message(ContactsManager *contacts_manager,
entities = find_entities(draft->message_, false, true);
}
result->input_message_text.text = FormattedText{std::move(draft->message_), std::move(entities)};
result->input_message_text.disable_web_page_preview = (flags & telegram_api::draftMessage::NO_WEBPAGE_MASK) != 0;
result->input_message_text.disable_web_page_preview = draft->no_webpage_;
result->input_message_text.clear_draft = false;
return result;

View File

@ -8,6 +8,7 @@
#include "td/telegram/AnimationsManager.h"
#include "td/telegram/BackgroundManager.h"
#include "td/telegram/ConfigManager.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/files/FileManager.h"
#include "td/telegram/Global.h"
@ -59,6 +60,7 @@ fileSourceFavoriteStickers = FileSource; // repa
fileSourceBackground background_id:int64 access_hash:int64 = FileSource; // repaired with account.getWallPaper
fileSourceBasicGroupFull basic_group_id:int32 = FileSource; // repaired with messages.getFullChat
fileSourceSupergroupFull supergroup_id:int32 = FileSource; // repaired with messages.getFullChannel
fileSourceAppConfig = FileSource; // repaired with help.getAppConfig, not reliable
*/
FileSourceId FileReferenceManager::get_current_file_source_id() const {
@ -118,6 +120,11 @@ FileSourceId FileReferenceManager::create_channel_full_file_source(ChannelId cha
return add_file_source_id(source, PSLICE() << "full " << channel_id);
}
FileSourceId FileReferenceManager::create_app_config_file_source() {
FileSourceAppConfig source;
return add_file_source_id(source, "app config");
}
bool FileReferenceManager::add_file_source(NodeId node_id, FileSourceId file_source_id) {
bool is_added = nodes_[node_id].file_source_ids.add(file_source_id);
VLOG(file_references) << "Add " << (is_added ? "new" : "old") << ' ' << file_source_id << " for file " << node_id;
@ -291,6 +298,9 @@ void FileReferenceManager::send_query(Destination dest, FileSourceId file_source
[&](const FileSourceChannelFull &source) {
send_closure_later(G()->contacts_manager(), &ContactsManager::reload_channel_full, source.channel_id,
std::move(promise), "repair file reference");
},
[&](const FileSourceAppConfig &source) {
send_closure_later(G()->config_manager(), &ConfigManager::reget_app_config, std::move(promise));
}));
}

View File

@ -51,6 +51,7 @@ class FileReferenceManager final : public Actor {
FileSourceId create_background_file_source(BackgroundId background_id, int64 access_hash);
FileSourceId create_chat_full_file_source(ChatId chat_id);
FileSourceId create_channel_full_file_source(ChannelId channel_id);
FileSourceId create_app_config_file_source();
using NodeId = FileId;
void repair_file_reference(NodeId node_id, Promise<> promise);
@ -134,12 +135,15 @@ class FileReferenceManager final : public Actor {
struct FileSourceChannelFull {
ChannelId channel_id;
};
struct FileSourceAppConfig {
// empty
};
// append only
using FileSource =
Variant<FileSourceMessage, FileSourceUserPhoto, FileSourceChatPhoto, FileSourceChannelPhoto, FileSourceWallpapers,
FileSourceWebPage, FileSourceSavedAnimations, FileSourceRecentStickers, FileSourceFavoriteStickers,
FileSourceBackground, FileSourceChatFull, FileSourceChannelFull>;
FileSourceBackground, FileSourceChatFull, FileSourceChannelFull, FileSourceAppConfig>;
vector<FileSource> file_sources_;
int64 query_generation_{0};

View File

@ -49,7 +49,8 @@ void FileReferenceManager::store_file_source(FileSourceId file_source_id, Storer
td::store(source.access_hash, storer);
},
[&](const FileSourceChatFull &source) { td::store(source.chat_id, storer); },
[&](const FileSourceChannelFull &source) { td::store(source.channel_id, storer); }));
[&](const FileSourceChannelFull &source) { td::store(source.channel_id, storer); },
[&](const FileSourceAppConfig &source) {}));
}
template <class ParserT>
@ -111,6 +112,8 @@ FileSourceId FileReferenceManager::parse_file_source(Td *td, ParserT &parser) {
td::parse(channel_id, parser);
return td->contacts_manager_->get_channel_full_file_source_id(channel_id);
}
case 12:
return td->stickers_manager_->get_app_config_file_source_id();
default:
parser.set_error("Invalid type in FileSource");
return FileSourceId();

View File

@ -6,9 +6,6 @@
//
#include "td/telegram/Game.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/AnimationsManager.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/Document.h"

View File

@ -32,7 +32,7 @@ GroupCallParticipant::GroupCallParticipant(const tl_object_ptr<telegram_api::gro
LOG(ERROR) << "Receive " << to_string(participant);
volume_level = 10000;
}
is_volume_level_local = (participant->flags_ & telegram_api::groupCallParticipant::VOLUME_BY_ADMIN_MASK) == 0;
is_volume_level_local = !participant->volume_by_admin_;
}
if (!participant->left_) {
joined_date = participant->date_;

View File

@ -6,11 +6,6 @@
//
#include "td/telegram/InlineQueriesManager.h"
#include "td/telegram/td_api.h"
#include "td/telegram/td_api.hpp"
#include "td/telegram/telegram_api.h"
#include "td/telegram/telegram_api.hpp"
#include "td/telegram/AccessRights.h"
#include "td/telegram/AnimationsManager.h"
#include "td/telegram/AudiosManager.h"
@ -31,19 +26,20 @@
#include "td/telegram/MessageEntity.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/misc.h"
#include "td/telegram/net/DcId.h"
#include "td/telegram/Payments.h"
#include "td/telegram/Photo.h"
#include "td/telegram/ReplyMarkup.h"
#include "td/telegram/StickersManager.h"
#include "td/telegram/Td.h"
#include "td/telegram/td_api.hpp"
#include "td/telegram/TdDb.h"
#include "td/telegram/TdParameters.h"
#include "td/telegram/telegram_api.hpp"
#include "td/telegram/Venue.h"
#include "td/telegram/VideosManager.h"
#include "td/telegram/VoiceNotesManager.h"
#include "td/telegram/net/DcId.h"
#include "td/utils/algorithm.h"
#include "td/utils/base64.h"
#include "td/utils/buffer.h"

View File

@ -217,6 +217,15 @@ int32 get_json_value_int(telegram_api::object_ptr<telegram_api::JSONValue> &&jso
return 0;
}
double get_json_value_double(telegram_api::object_ptr<telegram_api::JSONValue> &&json_value, Slice name) {
CHECK(json_value != nullptr);
if (json_value->get_id() == telegram_api::jsonNumber::ID) {
return static_cast<const telegram_api::jsonNumber *>(json_value.get())->value_;
}
LOG(ERROR) << "Expected Double as " << name << ", but found " << to_string(json_value);
return 0.0;
}
string get_json_value_string(telegram_api::object_ptr<telegram_api::JSONValue> &&json_value, Slice name) {
CHECK(json_value != nullptr);
if (json_value->get_id() == telegram_api::jsonString::ID) {

View File

@ -30,6 +30,8 @@ bool get_json_value_bool(telegram_api::object_ptr<telegram_api::JSONValue> &&jso
int32 get_json_value_int(telegram_api::object_ptr<telegram_api::JSONValue> &&json_value, Slice name);
double get_json_value_double(telegram_api::object_ptr<telegram_api::JSONValue> &&json_value, Slice name);
string get_json_value_string(telegram_api::object_ptr<telegram_api::JSONValue> &&json_value, Slice name);
} // namespace td

View File

@ -12,11 +12,7 @@
#include "td/telegram/misc.h"
#include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/Td.h"
#include "td/telegram/misc.h"
#include "td/telegram/td_api.h"
#include "td/telegram/td_api.hpp"
#include "td/telegram/telegram_api.h"
#include "td/db/DbKey.h"
#include "td/db/SqliteDb.h"
@ -1609,9 +1605,9 @@ Result<LanguagePackManager::LanguageInfo> LanguagePackManager::get_language_info
info.native_name_ = std::move(language->native_name_);
info.base_language_code_ = std::move(language->base_lang_code_);
info.plural_code_ = std::move(language->plural_code_);
info.is_official_ = (language->flags_ & telegram_api::langPackLanguage::OFFICIAL_MASK) != 0;
info.is_rtl_ = (language->flags_ & telegram_api::langPackLanguage::RTL_MASK) != 0;
info.is_beta_ = (language->flags_ & telegram_api::langPackLanguage::BETA_MASK) != 0;
info.is_official_ = language->official_;
info.is_rtl_ = language->rtl_;
info.is_beta_ = language->beta_;
info.is_from_database_ = false;
info.total_string_count_ = language->strings_count_;
info.translated_string_count_ = language->translated_count_;

View File

@ -7,7 +7,6 @@
#pragma once
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"

View File

@ -354,13 +354,19 @@ class LinkManager::InternalLinkUnknownDeepLink final : public InternalLink {
}
};
class LinkManager::InternalLinkUnsupportedProxy final : public InternalLink {
td_api::object_ptr<td_api::InternalLinkType> get_internal_link_type_object() const final {
return td_api::make_object<td_api::internalLinkTypeUnsupportedProxy>();
}
};
class LinkManager::InternalLinkVoiceChat final : public InternalLink {
string dialog_username_;
string invite_hash_;
bool is_live_stream_;
td_api::object_ptr<td_api::InternalLinkType> get_internal_link_type_object() const final {
return td_api::make_object<td_api::internalLinkTypeVoiceChat>(dialog_username_, invite_hash_, is_live_stream_);
return td_api::make_object<td_api::internalLinkTypeVideoChat>(dialog_username_, invite_hash_, is_live_stream_);
}
public:
@ -395,8 +401,6 @@ class GetDeepLinkInfoQuery final : public Td::ResultHandler {
return promise_.set_value(nullptr);
case telegram_api::help_deepLinkInfo::ID: {
auto info = telegram_api::move_object_as<telegram_api::help_deepLinkInfo>(result);
bool need_update = (info->flags_ & telegram_api::help_deepLinkInfo::UPDATE_APP_MASK) != 0;
auto entities = get_message_entities(nullptr, std::move(info->entities_), "GetDeepLinkInfoQuery");
auto status = fix_formatted_text(info->message_, entities, true, true, true, true, true);
if (status.is_error()) {
@ -408,7 +412,7 @@ class GetDeepLinkInfoQuery final : public Td::ResultHandler {
}
FormattedText text{std::move(info->message_), std::move(entities)};
return promise_.set_value(
td_api::make_object<td_api::deepLinkInfo>(get_formatted_text_object(text, true, -1), need_update));
td_api::make_object<td_api::deepLinkInfo>(get_formatted_text_object(text, true, -1), info->update_app_));
}
default:
UNREACHABLE();
@ -463,11 +467,9 @@ class RequestUrlAuthQuery final : public Td::ResultHandler {
return on_error(id, Status::Error(500, "Receive invalid bot_user_id"));
}
td->contacts_manager_->on_get_user(std::move(request->bot_), "RequestUrlAuthQuery");
bool request_write_access =
(request->flags_ & telegram_api::urlAuthResultRequest::REQUEST_WRITE_ACCESS_MASK) != 0;
promise_.set_value(td_api::make_object<td_api::loginUrlInfoRequestConfirmation>(
url_, request->domain_, td->contacts_manager_->get_user_id_object(bot_user_id, "RequestUrlAuthQuery"),
request_write_access));
request->request_write_access_));
break;
}
case telegram_api::urlAuthResultAccepted::ID: {
@ -863,6 +865,8 @@ unique_ptr<LinkManager::InternalLink> LinkManager::parse_tg_link_query(Slice que
if (0 < port && port < 65536) {
return td::make_unique<InternalLinkProxy>(
get_arg("server"), port, td_api::make_object<td_api::proxyTypeSocks5>(get_arg("user"), get_arg("pass")));
} else {
return td::make_unique<InternalLinkUnsupportedProxy>();
}
}
} else if (path.size() == 1 && path[0] == "proxy") {
@ -872,6 +876,8 @@ unique_ptr<LinkManager::InternalLink> LinkManager::parse_tg_link_query(Slice que
if (0 < port && port < 65536 && mtproto::ProxySecret::from_link(get_arg("secret")).is_ok()) {
return td::make_unique<InternalLinkProxy>(get_arg("server"), port,
td_api::make_object<td_api::proxyTypeMtproto>(get_arg("secret")));
} else {
return td::make_unique<InternalLinkUnsupportedProxy>();
}
}
} else if (path.size() == 1 && path[0] == "privatepost") {
@ -982,6 +988,8 @@ unique_ptr<LinkManager::InternalLink> LinkManager::parse_t_me_link_query(Slice q
if (0 < port && port < 65536) {
return td::make_unique<InternalLinkProxy>(
get_arg("server"), port, td_api::make_object<td_api::proxyTypeSocks5>(get_arg("user"), get_arg("pass")));
} else {
return td::make_unique<InternalLinkUnsupportedProxy>();
}
}
} else if (path[0] == "proxy") {
@ -991,6 +999,8 @@ unique_ptr<LinkManager::InternalLink> LinkManager::parse_t_me_link_query(Slice q
if (0 < port && port < 65536 && mtproto::ProxySecret::from_link(get_arg("secret")).is_ok()) {
return td::make_unique<InternalLinkProxy>(get_arg("server"), port,
td_api::make_object<td_api::proxyTypeMtproto>(get_arg("secret")));
} else {
return td::make_unique<InternalLinkUnsupportedProxy>();
}
}
} else if (path[0] == "bg") {
@ -1156,14 +1166,14 @@ void LinkManager::get_external_link_info(string &&link, Promise<td_api::object_p
}
if (autologin_update_time_ < Time::now() - 10000) {
auto query_promise = PromiseCreator::lambda([link = std::move(link), promise = std::move(promise)](
Result<td_api::object_ptr<td_api::JsonValue>> &&result) mutable {
if (result.is_error()) {
return promise.set_value(td_api::make_object<td_api::loginUrlInfoOpen>(link, false));
}
send_closure(G()->link_manager(), &LinkManager::get_external_link_info, std::move(link), std::move(promise));
});
return send_closure(G()->config_manager(), &ConfigManager::get_app_config, std::move(query_promise));
auto query_promise =
PromiseCreator::lambda([link = std::move(link), promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
return promise.set_value(td_api::make_object<td_api::loginUrlInfoOpen>(link, false));
}
send_closure(G()->link_manager(), &LinkManager::get_external_link_info, std::move(link), std::move(promise));
});
return send_closure(G()->config_manager(), &ConfigManager::reget_app_config, std::move(query_promise));
}
if (autologin_token_.empty()) {

View File

@ -98,6 +98,7 @@ class LinkManager final : public Actor {
class InternalLinkTheme;
class InternalLinkThemeSettings;
class InternalLinkUnknownDeepLink;
class InternalLinkUnsupportedProxy;
class InternalLinkVoiceChat;
struct LinkInfo {

View File

@ -7,9 +7,8 @@
#pragma once
#include "td/telegram/Global.h"
#include "td/telegram/SecretInputMedia.h"
#include "td/telegram/secret_api.h"
#include "td/telegram/SecretInputMedia.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"

View File

@ -8,7 +8,6 @@
#include "td/telegram/Client.h"
#include "td/telegram/Logging.h"
#include "td/telegram/td_api.h"
#include "td/utils/common.h"

View File

@ -319,6 +319,12 @@ class MessageChatAddUsers final : public MessageContent {
class MessageChatJoinedByLink final : public MessageContent {
public:
bool is_approved = false;
MessageChatJoinedByLink() = default;
explicit MessageChatJoinedByLink(bool is_approved) : is_approved(is_approved) {
}
MessageContentType get_type() const final {
return MessageContentType::ChatJoinedByLink;
}
@ -866,8 +872,13 @@ static void store(const MessageContent *content, StorerT &storer) {
store(m->user_ids, storer);
break;
}
case MessageContentType::ChatJoinedByLink:
case MessageContentType::ChatJoinedByLink: {
auto m = static_cast<const MessageChatJoinedByLink *>(content);
BEGIN_STORE_FLAGS();
STORE_FLAG(m->is_approved);
END_STORE_FLAGS();
break;
}
case MessageContentType::ChatDeleteUser: {
const auto *m = static_cast<const MessageChatDeleteUser *>(content);
store(m->user_id, storer);
@ -1229,9 +1240,18 @@ static void parse(unique_ptr<MessageContent> &content, ParserT &parser) {
content = std::move(m);
break;
}
case MessageContentType::ChatJoinedByLink:
content = make_unique<MessageChatJoinedByLink>();
case MessageContentType::ChatJoinedByLink: {
auto m = make_unique<MessageChatJoinedByLink>();
if (parser.version() >= static_cast<int32>(Version::AddInviteLinksRequiringApproval)) {
BEGIN_PARSE_FLAGS();
PARSE_FLAG(m->is_approved);
END_PARSE_FLAGS();
} else {
m->is_approved = false;
}
content = std::move(m);
break;
}
case MessageContentType::ChatDeleteUser: {
auto m = make_unique<MessageChatDeleteUser>();
parse(m->user_id, parser);
@ -1492,8 +1512,7 @@ InlineMessageContent create_inline_message_content(Td *td, FileId file_id,
break;
}
result.disable_web_page_preview =
(inline_message->flags_ & telegram_api::botInlineMessageText::NO_WEBPAGE_MASK) != 0;
result.disable_web_page_preview = inline_message->no_webpage_;
WebPageId web_page_id;
if (!result.disable_web_page_preview) {
web_page_id = td->web_pages_manager_->get_web_page_by_url(get_first_url(inline_message->message_, entities));
@ -3141,7 +3160,8 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo
old_file_view.main_remote_location().get_access_hash() !=
new_file_view.remote_location().get_access_hash()) {
FileId file_id = td->file_manager_->register_remote(
FullRemoteFileLocation({FileType::Photo, 'i'}, new_file_view.remote_location().get_id(),
FullRemoteFileLocation(PhotoSizeSource::thumbnail(FileType::Photo, 'i'),
new_file_view.remote_location().get_id(),
new_file_view.remote_location().get_access_hash(), DcId::invalid(),
new_file_view.remote_location().get_file_reference().str()),
FileLocationSource::FromServer, dialog_id, old_photo->photos.back().size, 0, "");
@ -3255,8 +3275,14 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo
}
break;
}
case MessageContentType::ChatJoinedByLink:
case MessageContentType::ChatJoinedByLink: {
auto old_ = static_cast<const MessageChatJoinedByLink *>(old_content);
auto new_ = static_cast<const MessageChatJoinedByLink *>(new_content);
if (old_->is_approved != new_->is_approved) {
need_update = true;
}
break;
}
case MessageContentType::ChatDeleteUser: {
const auto *old_ = static_cast<const MessageChatDeleteUser *>(old_content);
const auto *new_ = static_cast<const MessageChatDeleteUser *>(new_content);
@ -3584,12 +3610,22 @@ bool merge_message_content_file_id(Td *td, MessageContent *message_content, File
return false;
}
static bool can_be_animated_emoji(const FormattedText &text) {
return text.entities.empty() && is_emoji(text.text);
}
void register_message_content(Td *td, const MessageContent *content, FullMessageId full_message_id,
const char *source) {
switch (content->get_type()) {
case MessageContentType::Text:
return td->web_pages_manager_->register_web_page(static_cast<const MessageText *>(content)->web_page_id,
full_message_id, source);
case MessageContentType::Text: {
auto text = static_cast<const MessageText *>(content);
if (text->web_page_id.is_valid()) {
td->web_pages_manager_->register_web_page(text->web_page_id, full_message_id, source);
} else if (can_be_animated_emoji(text->text)) {
td->stickers_manager_->register_emoji(text->text.text, full_message_id, source);
}
return;
}
case MessageContentType::Poll:
return td->poll_manager_->register_poll(static_cast<const MessagePoll *>(content)->poll_id, full_message_id,
source);
@ -3608,12 +3644,16 @@ void reregister_message_content(Td *td, const MessageContent *old_content, const
auto new_content_type = new_content->get_type();
if (old_content_type == new_content_type) {
switch (old_content_type) {
case MessageContentType::Text:
if (static_cast<const MessageText *>(old_content)->web_page_id ==
static_cast<const MessageText *>(new_content)->web_page_id) {
case MessageContentType::Text: {
auto old_text = static_cast<const MessageText *>(old_content);
auto new_text = static_cast<const MessageText *>(new_content);
if (old_text->web_page_id == new_text->web_page_id &&
(old_text->text == new_text->text ||
(!can_be_animated_emoji(old_text->text) && !can_be_animated_emoji(new_text->text)))) {
return;
}
break;
}
case MessageContentType::Poll:
if (static_cast<const MessagePoll *>(old_content)->poll_id ==
static_cast<const MessagePoll *>(new_content)->poll_id) {
@ -3639,9 +3679,15 @@ void reregister_message_content(Td *td, const MessageContent *old_content, const
void unregister_message_content(Td *td, const MessageContent *content, FullMessageId full_message_id,
const char *source) {
switch (content->get_type()) {
case MessageContentType::Text:
return td->web_pages_manager_->unregister_web_page(static_cast<const MessageText *>(content)->web_page_id,
full_message_id, source);
case MessageContentType::Text: {
auto text = static_cast<const MessageText *>(content);
if (text->web_page_id.is_valid()) {
td->web_pages_manager_->unregister_web_page(text->web_page_id, full_message_id, source);
} else if (can_be_animated_emoji(text->text)) {
td->stickers_manager_->unregister_emoji(text->text.text, full_message_id, source);
}
return;
}
case MessageContentType::Poll:
return td->poll_manager_->unregister_poll(static_cast<const MessagePoll *>(content)->poll_id, full_message_id,
source);
@ -3803,9 +3849,9 @@ static auto secret_to_telegram_document(secret_api::decryptedMessageMediaExterna
}
vector<telegram_api::object_ptr<telegram_api::PhotoSize>> thumbnails;
thumbnails.push_back(secret_to_telegram<telegram_api::PhotoSize>(*from.thumb_));
return make_tl_object<telegram_api::document>(
telegram_api::document::THUMBS_MASK, from.id_, from.access_hash_, BufferSlice(), from.date_, from.mime_type_,
from.size_, std::move(thumbnails), Auto(), from.dc_id_, secret_to_telegram(from.attributes_));
return make_tl_object<telegram_api::document>(0, from.id_, from.access_hash_, BufferSlice(), from.date_,
from.mime_type_, from.size_, std::move(thumbnails), Auto(), from.dc_id_,
secret_to_telegram(from.attributes_));
}
template <class ToT, class FromT>
@ -4056,11 +4102,14 @@ unique_ptr<MessageContent> get_secret_message_content(
unique_ptr<MessageContent> get_message_content(Td *td, FormattedText message,
tl_object_ptr<telegram_api::MessageMedia> &&media,
DialogId owner_dialog_id, bool is_content_read, UserId via_bot_user_id,
int32 *ttl) {
int32 *ttl, bool *disable_web_page_preview) {
if (!td->auth_manager_->was_authorized() && !G()->close_flag() && media != nullptr) {
LOG(ERROR) << "Receive without authorization " << to_string(media);
media = nullptr;
}
if (disable_web_page_preview != nullptr) {
*disable_web_page_preview = false;
}
int32 constructor_id = media == nullptr ? telegram_api::messageMediaEmpty::ID : media->get_id();
switch (constructor_id) {
@ -4068,10 +4117,13 @@ unique_ptr<MessageContent> get_message_content(Td *td, FormattedText message,
if (message.text.empty()) {
LOG(ERROR) << "Receive empty message text and media for message from " << owner_dialog_id;
}
if (disable_web_page_preview != nullptr) {
*disable_web_page_preview = true;
}
return make_unique<MessageText>(std::move(message), WebPageId());
case telegram_api::messageMediaPhoto::ID: {
auto message_photo = move_tl_object_as<telegram_api::messageMediaPhoto>(media);
if ((message_photo->flags_ & telegram_api::messageMediaPhoto::PHOTO_MASK) == 0) {
if (message_photo->photo_ == nullptr) {
if ((message_photo->flags_ & telegram_api::messageMediaPhoto::TTL_SECONDS_MASK) == 0) {
LOG(ERROR) << "Receive messageMediaPhoto without photo and TTL: " << oneline(to_string(message_photo));
break;
@ -4151,7 +4203,7 @@ unique_ptr<MessageContent> get_message_content(Td *td, FormattedText message,
}
case telegram_api::messageMediaDocument::ID: {
auto message_document = move_tl_object_as<telegram_api::messageMediaDocument>(media);
if ((message_document->flags_ & telegram_api::messageMediaDocument::DOCUMENT_MASK) == 0) {
if (message_document->document_ == nullptr) {
if ((message_document->flags_ & telegram_api::messageMediaDocument::TTL_SECONDS_MASK) == 0) {
LOG(ERROR) << "Receive messageMediaDocument without document and TTL: "
<< oneline(to_string(message_document));
@ -4189,6 +4241,9 @@ unique_ptr<MessageContent> get_message_content(Td *td, FormattedText message,
get_input_invoice(move_tl_object_as<telegram_api::messageMediaInvoice>(media), td, owner_dialog_id));
case telegram_api::messageMediaWebPage::ID: {
auto media_web_page = move_tl_object_as<telegram_api::messageMediaWebPage>(media);
if (disable_web_page_preview != nullptr) {
*disable_web_page_preview = (media_web_page->webpage_ == nullptr);
}
auto web_page_id = td->web_pages_manager_->on_get_web_page(std::move(media_web_page->webpage_), owner_dialog_id);
return make_unique<MessageText>(std::move(message), web_page_id);
}
@ -4208,6 +4263,9 @@ unique_ptr<MessageContent> get_message_content(Td *td, FormattedText message,
}
// explicit empty media message
if (disable_web_page_preview != nullptr) {
*disable_web_page_preview = true;
}
return make_unique<MessageText>(std::move(message), WebPageId());
}
@ -4520,7 +4578,7 @@ unique_ptr<MessageContent> get_action_message_content(Td *td, tl_object_ptr<tele
return td::make_unique<MessageChatAddUsers>(std::move(user_ids));
}
case telegram_api::messageActionChatJoinedByLink::ID:
return make_unique<MessageChatJoinedByLink>();
return make_unique<MessageChatJoinedByLink>(false);
case telegram_api::messageActionChatDeleteUser::ID: {
auto chat_delete_user = move_tl_object_as<telegram_api::messageActionChatDeleteUser>(action);
@ -4590,13 +4648,12 @@ unique_ptr<MessageContent> get_action_message_content(Td *td, tl_object_ptr<tele
auto phone_call = move_tl_object_as<telegram_api::messageActionPhoneCall>(action);
auto duration =
(phone_call->flags_ & telegram_api::messageActionPhoneCall::DURATION_MASK) != 0 ? phone_call->duration_ : 0;
auto is_video = (phone_call->flags_ & telegram_api::messageActionPhoneCall::VIDEO_MASK) != 0;
if (duration < 0) {
LOG(ERROR) << "Receive invalid " << oneline(to_string(phone_call));
break;
}
return make_unique<MessageCall>(phone_call->call_id_, duration, get_call_discard_reason(phone_call->reason_),
is_video);
phone_call->video_);
}
case telegram_api::messageActionPaymentSent::ID: {
if (td->auth_manager_->is_bot()) {
@ -4715,6 +4772,8 @@ unique_ptr<MessageContent> get_action_message_content(Td *td, tl_object_ptr<tele
auto set_chat_theme = move_tl_object_as<telegram_api::messageActionSetChatTheme>(action);
return td::make_unique<MessageChatSetTheme>(std::move(set_chat_theme->emoticon_));
}
case telegram_api::messageActionChatJoinedByRequest::ID:
return make_unique<MessageChatJoinedByLink>(true);
default:
UNREACHABLE();
}
@ -4783,6 +4842,12 @@ tl_object_ptr<td_api::MessageContent> get_message_content_object(const MessageCo
}
case MessageContentType::Text: {
const auto *m = static_cast<const MessageText *>(content);
if (can_be_animated_emoji(m->text) && !m->web_page_id.is_valid()) {
auto animated_emoji = td->stickers_manager_->get_animated_emoji_object(m->text.text);
if (animated_emoji != nullptr) {
return td_api::make_object<td_api::messageAnimatedEmoji>(std::move(animated_emoji), m->text.text);
}
}
return make_tl_object<td_api::messageText>(
get_formatted_text_object(m->text, skip_bot_commands, max_media_timestamp),
td->web_pages_manager_->get_web_page_object(m->web_page_id));
@ -4832,8 +4897,13 @@ tl_object_ptr<td_api::MessageContent> get_message_content_object(const MessageCo
return make_tl_object<td_api::messageChatAddMembers>(
td->contacts_manager_->get_user_ids_object(m->user_ids, "MessageChatAddUsers"));
}
case MessageContentType::ChatJoinedByLink:
case MessageContentType::ChatJoinedByLink: {
const MessageChatJoinedByLink *m = static_cast<const MessageChatJoinedByLink *>(content);
if (m->is_approved) {
return make_tl_object<td_api::messageChatJoinByRequest>();
}
return make_tl_object<td_api::messageChatJoinByLink>();
}
case MessageContentType::ChatDeleteUser: {
const auto *m = static_cast<const MessageChatDeleteUser *>(content);
return make_tl_object<td_api::messageChatDeleteMember>(
@ -4933,19 +5003,19 @@ tl_object_ptr<td_api::MessageContent> get_message_content_object(const MessageCo
case MessageContentType::GroupCall: {
const auto *m = static_cast<const MessageGroupCall *>(content);
if (m->duration >= 0) {
return make_tl_object<td_api::messageVoiceChatEnded>(m->duration);
return make_tl_object<td_api::messageVideoChatEnded>(m->duration);
} else {
auto group_call_id = td->group_call_manager_->get_group_call_id(m->input_group_call_id, DialogId()).get();
if (m->schedule_date > 0) {
return make_tl_object<td_api::messageVoiceChatScheduled>(group_call_id, m->schedule_date);
return make_tl_object<td_api::messageVideoChatScheduled>(group_call_id, m->schedule_date);
} else {
return make_tl_object<td_api::messageVoiceChatStarted>(group_call_id);
return make_tl_object<td_api::messageVideoChatStarted>(group_call_id);
}
}
}
case MessageContentType::InviteToGroupCall: {
const auto *m = static_cast<const MessageInviteToGroupCall *>(content);
return make_tl_object<td_api::messageInviteVoiceChatParticipants>(
return make_tl_object<td_api::messageInviteVideoChatParticipants>(
td->group_call_manager_->get_group_call_id(m->input_group_call_id, DialogId()).get(),
td->contacts_manager_->get_user_ids_object(m->user_ids, "MessageInviteToGroupCall"));
}
@ -5315,8 +5385,8 @@ void get_message_content_animated_emoji_click_sticker(const MessageContent *cont
return promise.set_error(Status::Error(400, "Message is not an animated emoji message"));
}
auto &text = static_cast<const MessageText *>(content)->text;
if (!text.entities.empty()) {
const auto &text = static_cast<const MessageText *>(content)->text;
if (!can_be_animated_emoji(text)) {
return promise.set_error(Status::Error(400, "Message is not an animated emoji message"));
}
td->stickers_manager_->get_animated_emoji_click_sticker(text.text, full_message_id, std::move(promise));

View File

@ -189,7 +189,7 @@ unique_ptr<MessageContent> get_secret_message_content(
unique_ptr<MessageContent> get_message_content(Td *td, FormattedText message_text,
tl_object_ptr<telegram_api::MessageMedia> &&media,
DialogId owner_dialog_id, bool is_content_read, UserId via_bot_user_id,
int32 *ttl);
int32 *ttl, bool *disable_web_page_preview);
enum class MessageContentDupType : int32 { Send, SendViaBot, Forward, Copy };

View File

@ -7,7 +7,6 @@
#include "td/telegram/MessagesDb.h"
#include "td/telegram/logevent/LogEvent.h"
#include "td/telegram/MessageSearchFilter.h"
#include "td/telegram/Version.h"
#include "td/db/SqliteConnectionSafe.h"
@ -231,6 +230,12 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
"ORDER BY rowid DESC LIMIT ?3) ORDER BY search_id DESC"));
for (int32 i = 0; i < MESSAGES_DB_INDEX_COUNT; i++) {
TRY_RESULT_ASSIGN(
get_message_ids_stmts_[i],
db_.get_statement(
PSLICE() << "SELECT message_id FROM messages WHERE dialog_id = ?1 AND message_id < ?2 AND (index_mask & "
<< (1 << i) << ") != 0 ORDER BY message_id DESC LIMIT 1000000"));
TRY_RESULT_ASSIGN(
get_messages_from_index_stmts_[i].desc_stmt_,
db_.get_statement(
@ -335,7 +340,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
if (search_id != 0) {
// add dialog_id to text
text += PSTRING() << " \a" << dialog_id.get();
if (index_mask) {
if (index_mask != 0) {
for (int i = 0; i < MESSAGES_DB_INDEX_COUNT; i++) {
if ((index_mask & (1 << i))) {
text += PSTRING() << " \a\a" << i;
@ -470,16 +475,16 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
return Status::Error("Not found");
}
MessageId received_message_id(stmt.view_int64(0));
MessagesDbDialogMessage result{received_message_id, BufferSlice(stmt.view_blob(1))};
Slice data = stmt.view_blob(1);
if (is_scheduled_server) {
CHECK(received_message_id.is_scheduled());
CHECK(received_message_id.is_scheduled_server());
CHECK(received_message_id.get_scheduled_server_message_id() == message_id.get_scheduled_server_message_id());
} else {
LOG_CHECK(received_message_id == message_id)
<< received_message_id << ' ' << message_id << ' ' << get_message_info(result, true).first;
<< received_message_id << ' ' << message_id << ' ' << get_message_info(received_message_id, data, true).first;
}
return std::move(result);
return MessagesDbDialogMessage{received_message_id, BufferSlice(data)};
}
Result<MessagesDbMessage> get_message_by_unique_message_id(ServerMessageId unique_message_id) final {
@ -612,10 +617,72 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
return std::make_pair(std::move(messages), next_expires_till);
}
Result<MessagesDbCalendar> get_dialog_message_calendar(MessagesDbDialogCalendarQuery query) final {
auto &stmt = get_messages_from_index_stmts_[message_search_filter_index(query.filter)].desc_stmt_;
SCOPE_EXIT {
stmt.reset();
};
int32 limit = 1000;
stmt.bind_int64(1, query.dialog_id.get()).ensure();
stmt.bind_int64(2, query.from_message_id.get()).ensure();
stmt.bind_int32(3, limit).ensure();
vector<MessagesDbDialogMessage> messages;
vector<int32> total_counts;
stmt.step().ensure();
int32 current_day = std::numeric_limits<int32>::max();
while (stmt.has_row()) {
auto data_slice = stmt.view_blob(0);
MessageId message_id(stmt.view_int64(1));
auto info = get_message_info(message_id, data_slice, false);
auto day = (query.tz_offset + info.second) / 86400;
if (day >= current_day) {
CHECK(!total_counts.empty());
total_counts.back()++;
} else {
current_day = day;
messages.push_back(MessagesDbDialogMessage{message_id, BufferSlice(data_slice)});
total_counts.push_back(1);
}
stmt.step().ensure();
}
return MessagesDbCalendar{std::move(messages), std::move(total_counts)};
}
Result<MessagesDbMessagePositions> get_dialog_sparse_message_positions(
MessagesDbGetDialogSparseMessagePositionsQuery query) final {
auto &stmt = get_message_ids_stmts_[message_search_filter_index(query.filter)];
SCOPE_EXIT {
stmt.reset();
};
stmt.bind_int64(1, query.dialog_id.get()).ensure();
stmt.bind_int64(2, query.from_message_id.get()).ensure();
vector<MessageId> message_ids;
stmt.step().ensure();
while (stmt.has_row()) {
message_ids.push_back(MessageId(stmt.view_int64(0)));
stmt.step().ensure();
}
int32 limit = min(query.limit, static_cast<int32>(message_ids.size()));
double delta = static_cast<double>(message_ids.size()) / limit;
vector<MessagesDbMessagePosition> positions;
positions.reserve(limit);
for (int32 i = 0; i < limit; i++) {
auto position = static_cast<int32>((i + 0.5) * delta);
auto message_id = message_ids[position];
TRY_RESULT(message, get_message({query.dialog_id, message_id}));
auto date = get_message_info(message).second;
positions.push_back(MessagesDbMessagePosition{position, date, message_id});
}
return MessagesDbMessagePositions{static_cast<int32>(message_ids.size()), std::move(positions)};
}
Result<vector<MessagesDbDialogMessage>> get_messages(MessagesDbMessagesQuery query) final {
if (query.index_mask != 0) {
return get_messages_from_index(query.dialog_id, query.from_message_id, query.index_mask, query.offset,
query.limit);
if (query.filter != MessageSearchFilter::Empty) {
return get_messages_from_index(query.dialog_id, query.from_message_id, query.filter, query.offset, query.limit);
}
return get_messages_impl(get_messages_stmt_, query.dialog_id, query.from_message_id, query.offset, query.limit);
}
@ -699,7 +766,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
get_messages_fts_stmt_.reset();
};
LOG(INFO) << tag("query", query.query) << query.dialog_id << tag("index_mask", query.index_mask)
LOG(INFO) << tag("query", query.query) << query.dialog_id << tag("filter", query.filter)
<< tag("from_search_id", query.from_search_id) << tag("limit", query.limit);
string words = prepare_query(query.query);
LOG(INFO) << tag("from", query.query) << tag("to", words);
@ -710,18 +777,8 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
}
// index_mask kludge
if (query.index_mask != 0) {
int index_i = -1;
for (int i = 0; i < MESSAGES_DB_INDEX_COUNT; i++) {
if (query.index_mask == (1 << i)) {
index_i = i;
break;
}
}
if (index_i == -1) {
return Status::Error("Union of index types is not supported");
}
words += PSTRING() << " \"\a\a" << index_i << "\"";
if (query.filter != MessageSearchFilter::Empty) {
words += PSTRING() << " \"\a\a" << message_search_filter_index(query.filter) << "\"";
}
auto &stmt = get_messages_fts_stmt_;
@ -750,44 +807,20 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
}
Result<vector<MessagesDbDialogMessage>> get_messages_from_index(DialogId dialog_id, MessageId from_message_id,
int32 index_mask, int32 offset, int32 limit) {
CHECK(index_mask != 0);
LOG_CHECK(index_mask < (1 << MESSAGES_DB_INDEX_COUNT)) << tag("index_mask", index_mask);
int index_i = -1;
for (int i = 0; i < MESSAGES_DB_INDEX_COUNT; i++) {
if (index_mask == (1 << i)) {
index_i = i;
break;
}
}
if (index_i == -1) {
return Status::Error("Union is not supported");
}
auto &stmt = get_messages_from_index_stmts_[index_i];
MessageSearchFilter filter, int32 offset,
int32 limit) {
auto &stmt = get_messages_from_index_stmts_[message_search_filter_index(filter)];
return get_messages_impl(stmt, dialog_id, from_message_id, offset, limit);
}
Result<MessagesDbCallsResult> get_calls(MessagesDbCallsQuery query) final {
CHECK(query.index_mask != 0);
LOG_CHECK(query.index_mask < (1 << MESSAGES_DB_INDEX_COUNT)) << tag("index_mask", query.index_mask);
int index_i = -1;
for (int i = 0; i < MESSAGES_DB_INDEX_COUNT; i++) {
if (query.index_mask == (1 << i)) {
index_i = i;
break;
}
}
if (index_i == -1) {
return Status::Error("Union is not supported");
}
int32 pos;
if (index_i + 1 == static_cast<int>(MessageSearchFilter::Call)) {
if (query.filter == MessageSearchFilter::Call) {
pos = 0;
} else if (index_i + 1 == static_cast<int>(MessageSearchFilter::MissedCall)) {
} else if (query.filter == MessageSearchFilter::MissedCall) {
pos = 1;
} else {
return Status::Error(PSLICE() << "Index mask is not Call or MissedCall " << query.index_mask);
return Status::Error(PSLICE() << "Filter is not Call or MissedCall: " << query.filter);
}
auto &stmt = get_calls_stmts_[pos];
@ -840,6 +873,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
SqliteStatement get_scheduled_messages_stmt_;
SqliteStatement get_messages_from_notification_id_stmt_;
std::array<SqliteStatement, MESSAGES_DB_INDEX_COUNT> get_message_ids_stmts_;
std::array<GetMessagesStmt, MESSAGES_DB_INDEX_COUNT> get_messages_from_index_stmts_;
std::array<SqliteStatement, 2> get_calls_stmts_;
@ -928,7 +962,11 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
}
static std::pair<MessageId, int32> get_message_info(const MessagesDbDialogMessage &message, bool from_data = false) {
LogEventParser message_date_parser(message.data.as_slice());
return get_message_info(message.message_id, message.data.as_slice(), from_data);
}
static std::pair<MessageId, int32> get_message_info(MessageId message_id, Slice data, bool from_data) {
LogEventParser message_date_parser(data);
int32 flags;
int32 flags2 = 0;
int32 flags3 = 0;
@ -940,17 +978,17 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
}
}
bool has_sender = (flags & (1 << 10)) != 0;
MessageId message_id;
td::parse(message_id, message_date_parser);
MessageId data_message_id;
td::parse(data_message_id, message_date_parser);
UserId sender_user_id;
if (has_sender) {
td::parse(sender_user_id, message_date_parser);
}
int32 date;
td::parse(date, message_date_parser);
LOG(INFO) << "Loaded " << message.message_id << "(aka " << message_id << ") sent at " << date << " by "
LOG(INFO) << "Loaded " << message_id << "(aka " << data_message_id << ") sent at " << date << " by "
<< sender_user_id;
return {from_data ? message_id : message.message_id, date};
return {from_data ? data_message_id : message_id, date};
}
};
@ -1016,6 +1054,15 @@ class MessagesDbAsync final : public MessagesDbAsyncInterface {
std::move(promise));
}
void get_dialog_message_calendar(MessagesDbDialogCalendarQuery query, Promise<MessagesDbCalendar> promise) final {
send_closure_later(impl_, &Impl::get_dialog_message_calendar, std::move(query), std::move(promise));
}
void get_dialog_sparse_message_positions(MessagesDbGetDialogSparseMessagePositionsQuery query,
Promise<MessagesDbMessagePositions> promise) final {
send_closure_later(impl_, &Impl::get_dialog_sparse_message_positions, std::move(query), std::move(promise));
}
void get_messages(MessagesDbMessagesQuery query, Promise<vector<MessagesDbDialogMessage>> promise) final {
send_closure_later(impl_, &Impl::get_messages, std::move(query), std::move(promise));
}
@ -1107,6 +1154,17 @@ class MessagesDbAsync final : public MessagesDbAsyncInterface {
promise.set_result(sync_db_->get_dialog_message_by_date(dialog_id, first_message_id, last_message_id, date));
}
void get_dialog_message_calendar(MessagesDbDialogCalendarQuery query, Promise<MessagesDbCalendar> promise) {
add_read_query();
promise.set_result(sync_db_->get_dialog_message_calendar(std::move(query)));
}
void get_dialog_sparse_message_positions(MessagesDbGetDialogSparseMessagePositionsQuery query,
Promise<MessagesDbMessagePositions> promise) {
add_read_query();
promise.set_result(sync_db_->get_dialog_sparse_message_positions(std::move(query)));
}
void get_messages(MessagesDbMessagesQuery query, Promise<vector<MessagesDbDialogMessage>> promise) {
add_read_query();
promise.set_result(sync_db_->get_messages(std::move(query)));

View File

@ -9,6 +9,7 @@
#include "td/telegram/DialogId.h"
#include "td/telegram/FullMessageId.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/MessageSearchFilter.h"
#include "td/telegram/NotificationId.h"
#include "td/telegram/ServerMessageId.h"
@ -28,7 +29,7 @@ class SqliteDb;
struct MessagesDbMessagesQuery {
DialogId dialog_id;
int32 index_mask{0};
MessageSearchFilter filter{MessageSearchFilter::Empty};
MessageId from_message_id;
int32 offset{0};
int32 limit{100};
@ -45,10 +46,40 @@ struct MessagesDbMessage {
BufferSlice data;
};
struct MessagesDbDialogCalendarQuery {
DialogId dialog_id;
MessageSearchFilter filter{MessageSearchFilter::Empty};
MessageId from_message_id;
int32 tz_offset{0};
};
struct MessagesDbCalendar {
vector<MessagesDbDialogMessage> messages;
vector<int32> total_counts;
};
struct MessagesDbGetDialogSparseMessagePositionsQuery {
DialogId dialog_id;
MessageSearchFilter filter{MessageSearchFilter::Empty};
MessageId from_message_id;
int32 limit{0};
};
struct MessagesDbMessagePosition {
int32 position{0};
int32 date{0};
MessageId message_id;
};
struct MessagesDbMessagePositions {
int32 total_count{0};
vector<MessagesDbMessagePosition> positions;
};
struct MessagesDbFtsQuery {
string query;
DialogId dialog_id;
int32 index_mask{0};
MessageSearchFilter filter{MessageSearchFilter::Empty};
int64 from_search_id{0};
int32 limit{100};
};
@ -58,10 +89,11 @@ struct MessagesDbFtsResult {
};
struct MessagesDbCallsQuery {
int32 index_mask{0};
MessageSearchFilter filter{MessageSearchFilter::Empty};
int32 from_unique_message_id{0};
int32 limit{100};
};
struct MessagesDbCallsResult {
vector<MessagesDbMessage> messages;
};
@ -88,6 +120,11 @@ class MessagesDbSyncInterface {
virtual Result<MessagesDbDialogMessage> get_dialog_message_by_date(DialogId dialog_id, MessageId first_message_id,
MessageId last_message_id, int32 date) = 0;
virtual Result<MessagesDbCalendar> get_dialog_message_calendar(MessagesDbDialogCalendarQuery query) = 0;
virtual Result<MessagesDbMessagePositions> get_dialog_sparse_message_positions(
MessagesDbGetDialogSparseMessagePositionsQuery query) = 0;
virtual Result<vector<MessagesDbDialogMessage>> get_messages(MessagesDbMessagesQuery query) = 0;
virtual Result<vector<MessagesDbDialogMessage>> get_scheduled_messages(DialogId dialog_id, int32 limit) = 0;
virtual Result<vector<MessagesDbDialogMessage>> get_messages_from_notification_id(DialogId dialog_id,
@ -139,6 +176,12 @@ class MessagesDbAsyncInterface {
virtual void get_dialog_message_by_date(DialogId dialog_id, MessageId first_message_id, MessageId last_message_id,
int32 date, Promise<MessagesDbDialogMessage> promise) = 0;
virtual void get_dialog_message_calendar(MessagesDbDialogCalendarQuery query,
Promise<MessagesDbCalendar> promise) = 0;
virtual void get_dialog_sparse_message_positions(MessagesDbGetDialogSparseMessagePositionsQuery query,
Promise<MessagesDbMessagePositions> promise) = 0;
virtual void get_messages(MessagesDbMessagesQuery query, Promise<vector<MessagesDbDialogMessage>> promise) = 0;
virtual void get_scheduled_messages(DialogId dialog_id, int32 limit,
Promise<vector<MessagesDbDialogMessage>> promise) = 0;

File diff suppressed because it is too large Load Diff

View File

@ -48,14 +48,13 @@
#include "td/telegram/ReportReason.h"
#include "td/telegram/RestrictionReason.h"
#include "td/telegram/ScheduledServerMessageId.h"
#include "td/telegram/secret_api.h"
#include "td/telegram/SecretChatId.h"
#include "td/telegram/SecretInputMedia.h"
#include "td/telegram/ServerMessageId.h"
#include "td/telegram/UserId.h"
#include "td/telegram/secret_api.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/UserId.h"
#include "td/actor/actor.h"
#include "td/actor/MultiPromise.h"
@ -208,6 +207,13 @@ class MessagesManager final : public Actor {
vector<tl_object_ptr<telegram_api::Peer>> &&peers);
void on_failed_public_dialogs_search(const string &query, Status &&error);
void on_get_message_search_result_calendar(DialogId dialog_id, MessageId from_message_id, MessageSearchFilter filter,
int64 random_id, int32 total_count,
vector<tl_object_ptr<telegram_api::Message>> &&messages,
vector<tl_object_ptr<telegram_api::searchResultsCalendarPeriod>> &&periods,
Promise<Unit> &&promise);
void on_failed_get_message_search_result_calendar(DialogId dialog_id, int64 random_id);
void on_get_dialog_messages_search_result(DialogId dialog_id, const string &query, DialogId sender_dialog_id,
MessageId from_message_id, int32 offset, int32 limit,
MessageSearchFilter filter, MessageId top_thread_message_id,
@ -295,6 +301,9 @@ class MessagesManager final : public Actor {
void on_update_dialog_theme_name(DialogId dialog_id, string theme_name);
void on_update_dialog_pending_join_requests(DialogId dialog_id, int32 pending_join_request_count,
vector<int64> pending_requesters);
void on_update_dialog_has_scheduled_server_messages(DialogId dialog_id, bool has_scheduled_server_messages);
void on_update_dialog_folder_id(DialogId dialog_id, FolderId folder_id);
@ -365,6 +374,9 @@ class MessagesManager final : public Actor {
void delete_dialog_messages_from_user(DialogId dialog_id, UserId user_id, Promise<Unit> &&promise);
void delete_dialog_messages_by_date(DialogId dialog_id, int32 min_date, int32 max_date, bool revoke,
Promise<Unit> &&promise);
void on_dialog_deleted(DialogId dialog_id, Promise<Unit> &&promise);
void on_update_dialog_group_call_rights(DialogId dialog_id);
@ -692,6 +704,10 @@ class MessagesManager final : public Actor {
int32 limit, int64 &random_id,
Promise<Unit> &&promise);
td_api::object_ptr<td_api::messageCalendar> get_dialog_message_calendar(DialogId dialog_id, MessageId from_message_id,
MessageSearchFilter filter, int64 &random_id,
bool use_db, Promise<Unit> &&promise);
std::pair<int32, vector<MessageId>> search_dialog_messages(DialogId dialog_id, const string &query,
const td_api::object_ptr<td_api::MessageSender> &sender,
MessageId from_message_id, int32 offset, int32 limit,
@ -733,6 +749,15 @@ class MessagesManager final : public Actor {
void on_get_dialog_message_by_date_fail(int64 random_id);
void get_dialog_sparse_message_positions(DialogId dialog_id, MessageSearchFilter filter, MessageId from_message_id,
int32 limit,
Promise<td_api::object_ptr<td_api::messagePositions>> &&promise);
void on_get_dialog_sparse_message_positions(
DialogId dialog_id, MessageSearchFilter filter,
telegram_api::object_ptr<telegram_api::messages_searchResultsPositions> positions,
Promise<td_api::object_ptr<td_api::messagePositions>> &&promise);
void get_dialog_message_count(DialogId dialog_id, MessageSearchFilter filter, bool return_local,
Promise<int32> &&promise);
@ -779,6 +804,8 @@ class MessagesManager final : public Actor {
void on_dialog_linked_channel_updated(DialogId dialog_id, ChannelId old_linked_channel_id,
ChannelId new_linked_channel_id) const;
void drop_dialog_pending_join_requests(DialogId dialog_id);
void on_resolved_username(const string &username, DialogId dialog_id);
void drop_username(const string &username);
@ -944,6 +971,7 @@ class MessagesManager final : public Actor {
int32 date = 0;
int32 ttl_period = 0;
int32 ttl = 0;
bool disable_web_page_preview = false;
int64 random_id = 0;
tl_object_ptr<telegram_api::messageFwdHeader> forward_header;
MessageId reply_to_message_id;
@ -1180,6 +1208,8 @@ class MessagesManager final : public Actor {
InputGroupCallId expected_active_group_call_id;
DialogId default_join_group_call_as_dialog_id;
string theme_name;
int32 pending_join_request_count = 0;
vector<UserId> pending_join_request_user_ids;
FolderId folder_id;
vector<DialogListId> dialog_list_ids; // TODO replace with mask
@ -1628,21 +1658,21 @@ class MessagesManager final : public Actor {
};
class BlockMessageSenderFromRepliesOnServerLogEvent;
class ToggleDialogReportSpamStateOnServerLogEvent;
class DeleteAllCallMessagesOnServerLogEvent;
class DeleteAllChannelMessagesFromUserOnServerLogEvent;
class DeleteDialogHistoryFromServerLogEvent;
class DeleteAllCallMessagesFromServerLogEvent;
class DeleteDialogHistoryOnServerLogEvent;
class DeleteDialogMessagesByDateOnServerLogEvent;
class DeleteMessageLogEvent;
class DeleteMessagesFromServerLogEvent;
class DeleteScheduledMessagesFromServerLogEvent;
class DeleteMessagesOnServerLogEvent;
class DeleteScheduledMessagesOnServerLogEvent;
class ForwardMessagesLogEvent;
class GetChannelDifferenceLogEvent;
class GetDialogFromServerLogEvent;
class ReadAllDialogMentionsOnServerLogEvent;
class ReadHistoryInSecretChatLogEvent;
class ReadHistoryOnServerLogEvent;
class ReadMessageContentsOnServerLogEvent;
class ReadMessageThreadHistoryOnServerLogEvent;
class RegetDialogLogEvent;
class ReorderPinnedDialogsOnServerLogEvent;
class ResetAllNotificationSettingsOnServerLogEvent;
class SaveDialogDraftMessageOnServerLogEvent;
@ -1654,6 +1684,7 @@ class MessagesManager final : public Actor {
class ToggleDialogIsBlockedOnServerLogEvent;
class ToggleDialogIsMarkedAsUnreadOnServerLogEvent;
class ToggleDialogIsPinnedOnServerLogEvent;
class ToggleDialogReportSpamStateOnServerLogEvent;
class UnpinAllDialogMessagesOnServerLogEvent;
class UpdateDialogNotificationSettingsOnServerLogEvent;
class UpdateScopeNotificationSettingsOnServerLogEvent;
@ -1975,18 +2006,18 @@ class MessagesManager final : public Actor {
void do_delete_all_dialog_messages(Dialog *d, unique_ptr<Message> &message, bool is_permanently_deleted,
vector<int64> &deleted_message_ids);
void delete_sent_message_from_server(DialogId dialog_id, MessageId message_id);
void delete_sent_message_on_server(DialogId dialog_id, MessageId message_id);
void delete_messages_from_server(DialogId dialog_id, vector<MessageId> message_ids, bool revoke, uint64 log_event_id,
Promise<Unit> &&promise);
void delete_messages_on_server(DialogId dialog_id, vector<MessageId> message_ids, bool revoke, uint64 log_event_id,
Promise<Unit> &&promise);
void delete_scheduled_messages_from_server(DialogId dialog_id, vector<MessageId> message_ids, uint64 log_event_id,
Promise<Unit> &&promise);
void delete_scheduled_messages_on_server(DialogId dialog_id, vector<MessageId> message_ids, uint64 log_event_id,
Promise<Unit> &&promise);
void delete_dialog_history_from_server(DialogId dialog_id, MessageId max_message_id, bool remove_from_dialog_list,
bool revoke, bool allow_error, uint64 log_event_id, Promise<Unit> &&promise);
void delete_dialog_history_on_server(DialogId dialog_id, MessageId max_message_id, bool remove_from_dialog_list,
bool revoke, bool allow_error, uint64 log_event_id, Promise<Unit> &&promise);
void delete_all_call_messages_from_server(bool revoke, uint64 log_event_id, Promise<Unit> &&promise);
void delete_all_call_messages_on_server(bool revoke, uint64 log_event_id, Promise<Unit> &&promise);
void block_message_sender_from_replies_on_server(MessageId message_id, bool need_delete_message,
bool need_delete_all_messages, bool report_spam, uint64 log_event_id,
@ -1995,12 +2026,17 @@ class MessagesManager final : public Actor {
void delete_all_channel_messages_from_user_on_server(ChannelId channel_id, UserId user_id, 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,
uint64 log_event_id, Promise<Unit> &&promise);
void read_all_dialog_mentions_on_server(DialogId dialog_id, uint64 log_event_id, Promise<Unit> &&promise);
void unpin_all_dialog_messages_on_server(DialogId dialog_id, uint64 log_event_id, Promise<Unit> &&promise);
static MessageId find_message_by_date(const Message *m, int32 date);
static void find_messages_by_date(const Message *m, int32 min_date, int32 max_date, vector<MessageId> &message_ids);
static void find_messages(const Message *m, vector<MessageId> &message_ids,
const std::function<bool(const Message *)> &condition);
@ -2339,7 +2375,9 @@ class MessagesManager final : public Actor {
void send_update_chat_theme(const Dialog *d);
void send_update_chat_voice_chat(const Dialog *d);
void send_update_chat_pending_join_requests(const Dialog *d);
void send_update_chat_video_chat(const Dialog *d);
void send_update_chat_message_ttl_setting(const Dialog *d);
@ -2438,6 +2476,12 @@ class MessagesManager final : public Actor {
void set_dialog_theme_name(Dialog *d, string theme_name);
void fix_pending_join_requests(DialogId dialog_id, int32 &pending_join_request_count,
vector<UserId> &pending_join_request_user_ids) const;
void set_dialog_pending_join_requests(Dialog *d, int32 pending_join_request_count,
vector<UserId> pending_join_request_user_ids);
void repair_dialog_scheduled_messages(Dialog *d);
void set_dialog_has_scheduled_server_messages(Dialog *d, bool has_scheduled_server_messages);
@ -2530,7 +2574,9 @@ class MessagesManager final : public Actor {
string get_dialog_theme_name(const Dialog *d) const;
td_api::object_ptr<td_api::voiceChat> get_voice_chat_object(const Dialog *d) const;
td_api::object_ptr<td_api::chatJoinRequestsInfo> get_chat_join_requests_info_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::chat> get_chat_object(const Dialog *d) const;
@ -2774,13 +2820,17 @@ class MessagesManager final : public Actor {
static MessageId get_first_database_message_id_by_index(const Dialog *d, MessageSearchFilter filter);
void on_get_message_calendar_from_database(int64 random_id, DialogId dialog_id, MessageId from_message_id,
MessageId first_db_message_id, MessageSearchFilter filter,
Result<MessagesDbCalendar> r_calendar, Promise<Unit> promise);
void on_search_dialog_messages_db_result(int64 random_id, DialogId dialog_id, MessageId from_message_id,
MessageId first_db_message_id, MessageSearchFilter filter, int32 offset,
int32 limit, Result<vector<MessagesDbDialogMessage>> r_messages,
Promise<> promise);
Promise<Unit> promise);
void on_messages_db_fts_result(Result<MessagesDbFtsResult> result, string offset, int32 limit, int64 random_id,
Promise<> &&promise);
Promise<Unit> &&promise);
void on_messages_db_calls_result(Result<MessagesDbCallsResult> result, int64 random_id, MessageId first_db_message_id,
MessageSearchFilter filter, Promise<Unit> &&promise);
@ -2822,7 +2872,7 @@ class MessagesManager final : public Actor {
string get_dialog_username(DialogId dialog_id) const;
RestrictedRights get_dialog_permissions(DialogId dialog_id) const;
RestrictedRights get_dialog_default_permissions(DialogId dialog_id) const;
bool get_dialog_has_scheduled_messages(const Dialog *d) const;
@ -3044,16 +3094,16 @@ class MessagesManager final : public Actor {
static uint64 save_toggle_dialog_report_spam_state_on_server_log_event(DialogId dialog_id, bool is_spam_dialog);
static uint64 save_delete_messages_from_server_log_event(DialogId dialog_id, const vector<MessageId> &message_ids,
bool revoke);
static uint64 save_delete_messages_on_server_log_event(DialogId dialog_id, const vector<MessageId> &message_ids,
bool revoke);
static uint64 save_delete_scheduled_messages_from_server_log_event(DialogId dialog_id,
const vector<MessageId> &message_ids);
static uint64 save_delete_scheduled_messages_on_server_log_event(DialogId dialog_id,
const vector<MessageId> &message_ids);
static uint64 save_delete_dialog_history_from_server_log_event(DialogId dialog_id, MessageId max_message_id,
bool remove_from_dialog_list, bool revoke);
static uint64 save_delete_dialog_history_on_server_log_event(DialogId dialog_id, MessageId max_message_id,
bool remove_from_dialog_list, bool revoke);
static uint64 save_delete_all_call_messages_from_server_log_event(bool revoke);
static uint64 save_delete_all_call_messages_on_server_log_event(bool revoke);
static uint64 save_block_message_sender_from_replies_on_server_log_event(MessageId message_id,
bool need_delete_message,
@ -3062,6 +3112,9 @@ class MessagesManager final : public Actor {
static uint64 save_delete_all_channel_messages_from_user_on_server_log_event(ChannelId channel_id, UserId user_id);
static uint64 save_delete_dialog_messages_by_date_on_server_log_event(DialogId dialog_id, int32 min_date,
int32 max_date, bool revoke);
static uint64 save_read_all_dialog_mentions_on_server_log_event(DialogId dialog_id);
static uint64 save_toggle_dialog_is_pinned_on_server_log_event(DialogId dialog_id, bool is_pinned);
@ -3080,7 +3133,7 @@ class MessagesManager final : public Actor {
static uint64 save_reset_all_notification_settings_on_server_log_event();
static uint64 save_get_dialog_from_server_log_event(DialogId dialog_id);
static uint64 save_reget_dialog_log_event(DialogId dialog_id);
static uint64 save_forward_messages_log_event(DialogId to_dialog_id, DialogId from_dialog_id,
const vector<Message *> &messages,
@ -3289,6 +3342,7 @@ class MessagesManager final : public Actor {
std::unordered_map<int64, FullMessageId> get_dialog_message_by_date_results_;
std::unordered_map<int64, td_api::object_ptr<td_api::messageCalendar>> found_dialog_message_calendars_;
std::unordered_map<int64, std::pair<int32, vector<MessageId>>>
found_dialog_messages_; // random_id -> [total_count, [message_id]...]
std::unordered_map<int64, DialogId> found_dialog_messages_dialog_id_; // random_id -> dialog_id

View File

@ -2915,6 +2915,9 @@ string NotificationManager::convert_loc_key(const string &loc_key) {
if (loc_key == "CHAT_ADD_YOU") {
return "MESSAGE_CHAT_ADD_MEMBERS_YOU";
}
if (loc_key == "CHAT_REQ_JOINED") {
return "MESSAGE_CHAT_JOIN_BY_REQUEST";
}
break;
}
return string();
@ -3276,13 +3279,10 @@ Status NotificationManager::process_push_notification_payload(string payload, bo
}
}
int32 flags = telegram_api::user::FIRST_NAME_MASK | telegram_api::user::MIN_MASK;
int32 flags = USER_FLAG_IS_INACCESSIBLE;
if (sender_access_hash != -1) {
// set phone number flag to show that this is a full access hash
flags |= telegram_api::user::ACCESS_HASH_MASK | telegram_api::user::PHONE_MASK;
}
if (sender_photo != nullptr) {
flags |= telegram_api::user::PHOTO_MASK;
flags |= USER_FLAG_HAS_ACCESS_HASH | USER_FLAG_HAS_PHONE_NUMBER;
}
auto user_name = sender_user_id.get() == 136817688 ? "Channel" : sender_name;
auto user = telegram_api::make_object<telegram_api::user>(
@ -3620,7 +3620,7 @@ void NotificationManager::add_message_push_notification(DialogId dialog_id, Mess
}
if (sender_user_id.is_valid() && !td_->contacts_manager_->have_user_force(sender_user_id)) {
int32 flags = telegram_api::user::FIRST_NAME_MASK | telegram_api::user::MIN_MASK;
int32 flags = USER_FLAG_IS_INACCESSIBLE;
auto user_name = sender_user_id.get() == 136817688 ? "Channel" : sender_name;
auto user = telegram_api::make_object<telegram_api::user>(
flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,

View File

@ -150,6 +150,10 @@ class NotificationManager final : public Actor {
static constexpr int32 ANNOUNCEMENT_ID_CACHE_TIME = 7 * 86400;
static constexpr int32 USER_FLAG_HAS_ACCESS_HASH = 1 << 0;
static constexpr int32 USER_FLAG_HAS_PHONE_NUMBER = 1 << 4;
static constexpr int32 USER_FLAG_IS_INACCESSIBLE = 1 << 20;
class AddMessagePushNotificationLogEvent;
class EditMessagePushNotificationLogEvent;

View File

@ -213,6 +213,9 @@ class NotificationTypePushMessage final : public NotificationType {
if (key == "MESSAGE_CHAT_JOIN_BY_LINK") {
return td_api::make_object<td_api::pushMessageContentChatJoinByLink>();
}
if (key == "MESSAGE_CHAT_JOIN_BY_REQUEST") {
return td_api::make_object<td_api::pushMessageContentChatJoinByRequest>();
}
if (key == "MESSAGE_CONTACT") {
return td_api::make_object<td_api::pushMessageContentContact>(arg, is_pinned);
}

View File

@ -778,9 +778,8 @@ void PasswordManager::do_get_state(Promise<PasswordState> promise) {
state.current_srp_B = password->srp_B_.as_slice().str();
state.current_srp_id = password->srp_id_;
state.password_hint = std::move(password->hint_);
state.has_recovery_email_address =
(password->flags_ & telegram_api::account_password::HAS_RECOVERY_MASK) != 0;
state.has_secure_values = (password->flags_ & telegram_api::account_password::HAS_SECURE_VALUES_MASK) != 0;
state.has_recovery_email_address = password->has_recovery_;
state.has_secure_values = password->has_secure_values_;
} else {
state.has_password = false;
send_closure(actor_id, &PasswordManager::drop_cached_secret);

View File

@ -304,9 +304,8 @@ class GetPaymentFormQuery final : public Td::ResultHandler {
LOG(ERROR) << "Receive invalid seller " << seller_bot_user_id;
return on_error(id, Status::Error(500, "Receive invalid seller identifier"));
}
bool can_save_credentials =
(payment_form->flags_ & telegram_api::payments_paymentForm::CAN_SAVE_CREDENTIALS_MASK) != 0;
bool need_password = (payment_form->flags_ & telegram_api::payments_paymentForm::PASSWORD_MISSING_MASK) != 0;
bool can_save_credentials = payment_form->can_save_credentials_;
bool need_password = payment_form->password_missing_;
promise_.set_value(make_tl_object<td_api::paymentForm>(
payment_form->form_id_, convert_invoice(std::move(payment_form->invoice_)), std::move(payment_form->url_),
td->contacts_manager_->get_user_id_object(seller_bot_user_id, "paymentForm seller"),
@ -649,9 +648,8 @@ InputInvoice get_input_invoice(tl_object_ptr<telegram_api::messageMediaInvoice>
result.photo = get_web_document_photo(td->file_manager_.get(), std::move(message_invoice->photo_), owner_dialog_id);
result.start_parameter = std::move(message_invoice->start_param_);
result.invoice.currency = std::move(message_invoice->currency_);
result.invoice.is_test = (message_invoice->flags_ & telegram_api::messageMediaInvoice::TEST_MASK) != 0;
result.invoice.need_shipping_address =
(message_invoice->flags_ & telegram_api::messageMediaInvoice::SHIPPING_ADDRESS_REQUESTED_MASK) != 0;
result.invoice.is_test = message_invoice->test_;
result.invoice.need_shipping_address = message_invoice->shipping_address_requested_;
// result.payload = string();
// result.provider_token = string();
// result.provider_data = string();
@ -674,9 +672,8 @@ InputInvoice get_input_invoice(tl_object_ptr<telegram_api::botInlineMessageMedia
result.photo = get_web_document_photo(td->file_manager_.get(), std::move(message_invoice->photo_), owner_dialog_id);
// result.start_parameter = string();
result.invoice.currency = std::move(message_invoice->currency_);
result.invoice.is_test = (message_invoice->flags_ & telegram_api::messageMediaInvoice::TEST_MASK) != 0;
result.invoice.need_shipping_address =
(message_invoice->flags_ & telegram_api::messageMediaInvoice::SHIPPING_ADDRESS_REQUESTED_MASK) != 0;
result.invoice.is_test = message_invoice->test_;
result.invoice.need_shipping_address = message_invoice->shipping_address_requested_;
// result.payload = string();
// result.provider_token = string();
// result.provider_data = string();

View File

@ -163,17 +163,17 @@ ProfilePhoto get_profile_photo(FileManager *file_manager, UserId user_id, int64
auto profile_photo = move_tl_object_as<telegram_api::userProfilePhoto>(profile_photo_ptr);
auto dc_id = DcId::create(profile_photo->dc_id_);
result.has_animation = (profile_photo->flags_ & telegram_api::userProfilePhoto::HAS_VIDEO_MASK) != 0;
result.has_animation = profile_photo->has_video_;
result.id = profile_photo->photo_id_;
if (!G()->shared_config().get_option_boolean("disable_minithumbnails")) {
result.minithumbnail = profile_photo->stripped_thumb_.as_slice().str();
}
result.small_file_id =
register_photo(file_manager, {DialogId(user_id), user_access_hash, false}, result.id, 0 /*access_hash*/,
"" /*file_reference*/, DialogId(), 0 /*file_size*/, dc_id, PhotoFormat::Jpeg);
result.big_file_id =
register_photo(file_manager, {DialogId(user_id), user_access_hash, true}, result.id, 0 /*access_hash*/,
"" /*file_reference*/, DialogId(), 0 /*file_size*/, dc_id, PhotoFormat::Jpeg);
result.small_file_id = register_photo(
file_manager, PhotoSizeSource::dialog_photo(DialogId(user_id), user_access_hash, false), result.id,
0 /*access_hash*/, "" /*file_reference*/, DialogId(), 0 /*file_size*/, dc_id, PhotoFormat::Jpeg);
result.big_file_id = register_photo(
file_manager, PhotoSizeSource::dialog_photo(DialogId(user_id), user_access_hash, true), result.id,
0 /*access_hash*/, "" /*file_reference*/, DialogId(), 0 /*file_size*/, dc_id, PhotoFormat::Jpeg);
break;
}
default:
@ -227,12 +227,14 @@ DialogPhoto get_dialog_photo(FileManager *file_manager, DialogId dialog_id, int6
auto chat_photo = move_tl_object_as<telegram_api::chatPhoto>(chat_photo_ptr);
auto dc_id = DcId::create(chat_photo->dc_id_);
result.has_animation = (chat_photo->flags_ & telegram_api::chatPhoto::HAS_VIDEO_MASK) != 0;
result.has_animation = chat_photo->has_video_;
result.minithumbnail = chat_photo->stripped_thumb_.as_slice().str();
result.small_file_id = register_photo(file_manager, {dialog_id, dialog_access_hash, false}, chat_photo->photo_id_,
0, "", DialogId(), 0, dc_id, PhotoFormat::Jpeg);
result.big_file_id = register_photo(file_manager, {dialog_id, dialog_access_hash, true}, chat_photo->photo_id_, 0,
"", DialogId(), 0, dc_id, PhotoFormat::Jpeg);
result.small_file_id =
register_photo(file_manager, PhotoSizeSource::dialog_photo(dialog_id, dialog_access_hash, false),
chat_photo->photo_id_, 0, "", DialogId(), 0, dc_id, PhotoFormat::Jpeg);
result.big_file_id =
register_photo(file_manager, PhotoSizeSource::dialog_photo(dialog_id, dialog_access_hash, true),
chat_photo->photo_id_, 0, "", DialogId(), 0, dc_id, PhotoFormat::Jpeg);
break;
}
@ -299,7 +301,7 @@ ProfilePhoto as_profile_photo(FileManager *file_manager, UserId user_id, int64 u
auto remote = file_view.remote_location();
CHECK(remote.is_photo());
CHECK(!remote.is_web());
remote.set_source({DialogId(user_id), user_access_hash, is_big});
remote.set_source(PhotoSizeSource::dialog_photo(DialogId(user_id), user_access_hash, is_big));
return file_manager->register_remote(std::move(remote), FileLocationSource::FromServer, DialogId(),
file_view.size(), file_view.expected_size(), file_view.remote_name());
};
@ -341,7 +343,8 @@ PhotoSize get_secret_thumbnail_photo_size(FileManager *file_manager, BufferSlice
auto photo_id = -(Random::secure_int64() & std::numeric_limits<int64>::max());
res.file_id = file_manager->register_remote(
FullRemoteFileLocation(PhotoSizeSource(FileType::EncryptedThumbnail, 't'), photo_id, 0, dc_id, string()),
FullRemoteFileLocation(PhotoSizeSource::thumbnail(FileType::EncryptedThumbnail, 't'), photo_id, 0, dc_id,
string()),
FileLocationSource::FromServer, owner_dialog_id, res.size, 0,
PSTRING() << static_cast<uint64>(photo_id) << ".jpg");
file_manager->set_content(res.file_id, std::move(bytes));
@ -717,7 +720,7 @@ Photo get_photo(FileManager *file_manager, tl_object_ptr<telegram_api::photo> &&
res.id = photo->id_;
res.date = photo->date_;
res.has_stickers = (photo->flags_ & telegram_api::photo::HAS_STICKERS_MASK) != 0;
res.has_stickers = photo->has_stickers_;
if (res.is_empty()) {
LOG(ERROR) << "Receive photo with identifier " << res.id.get();
@ -726,9 +729,9 @@ Photo get_photo(FileManager *file_manager, tl_object_ptr<telegram_api::photo> &&
DcId dc_id = DcId::create(photo->dc_id_);
for (auto &size_ptr : photo->sizes_) {
auto photo_size = get_photo_size(file_manager, {FileType::Photo, 0}, photo->id_, photo->access_hash_,
photo->file_reference_.as_slice().str(), dc_id, owner_dialog_id,
std::move(size_ptr), PhotoFormat::Jpeg);
auto photo_size = get_photo_size(file_manager, PhotoSizeSource::thumbnail(FileType::Photo, 0), photo->id_,
photo->access_hash_, photo->file_reference_.as_slice().str(), dc_id,
owner_dialog_id, std::move(size_ptr), PhotoFormat::Jpeg);
if (photo_size.get_offset() == 0) {
PhotoSize &size = photo_size.get<0>();
if (size.type == 0 || size.type == 't' || size.type == 'i' || size.type == 'u' || size.type == 'v') {
@ -746,9 +749,9 @@ Photo get_photo(FileManager *file_manager, tl_object_ptr<telegram_api::photo> &&
}
for (auto &size_ptr : photo->video_sizes_) {
auto animation =
get_animation_size(file_manager, {FileType::Photo, 0}, photo->id_, photo->access_hash_,
photo->file_reference_.as_slice().str(), dc_id, owner_dialog_id, std::move(size_ptr));
auto animation = get_animation_size(file_manager, PhotoSizeSource::thumbnail(FileType::Photo, 0), photo->id_,
photo->access_hash_, photo->file_reference_.as_slice().str(), dc_id,
owner_dialog_id, std::move(size_ptr));
if (animation.type != 0 && animation.dimensions.width == animation.dimensions.height) {
res.animations.push_back(std::move(animation));
}
@ -996,12 +999,8 @@ tl_object_ptr<telegram_api::userProfilePhoto> convert_photo_to_profile_photo(
if (!have_photo_small || !have_photo_big) {
return nullptr;
}
int32 flags = 0;
if (!photo->video_sizes_.empty()) {
flags |= telegram_api::userProfilePhoto::HAS_VIDEO_MASK;
}
return make_tl_object<telegram_api::userProfilePhoto>(flags, false /*ignored*/, photo->id_, BufferSlice(),
photo->dc_id_);
bool has_video = !photo->video_sizes_.empty();
return make_tl_object<telegram_api::userProfilePhoto>(0, has_video, photo->id_, BufferSlice(), photo->dc_id_);
}
} // namespace td

View File

@ -218,7 +218,7 @@ static bool operator==(const PhotoSizeSource::StickerSetThumbnailVersion &lhs,
}
bool operator==(const PhotoSizeSource &lhs, const PhotoSizeSource &rhs) {
return lhs.variant == rhs.variant;
return lhs.variant_ == rhs.variant_;
}
bool operator!=(const PhotoSizeSource &lhs, const PhotoSizeSource &rhs) {

View File

@ -8,15 +8,12 @@
#include "td/telegram/DialogId.h"
#include "td/telegram/files/FileType.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/common.h"
#include "td/utils/StringBuilder.h"
#include "td/utils/Variant.h"
#include <cstddef>
namespace td {
struct PhotoSizeSource {
@ -141,37 +138,47 @@ struct PhotoSizeSource {
};
PhotoSizeSource() = default;
PhotoSizeSource(FileType file_type, int32 thumbnail_type) : variant(Thumbnail(file_type, thumbnail_type)) {
static PhotoSizeSource thumbnail(FileType file_type, int32 thumbnail_type) {
return PhotoSizeSource(Thumbnail(file_type, thumbnail_type));
}
PhotoSizeSource(DialogId dialog_id, int64 dialog_access_hash, bool is_big) {
static PhotoSizeSource dialog_photo(DialogId dialog_id, int64 dialog_access_hash, bool is_big) {
if (is_big) {
variant = DialogPhotoBig(dialog_id, dialog_access_hash);
return PhotoSizeSource(DialogPhotoBig(dialog_id, dialog_access_hash));
} else {
variant = DialogPhotoSmall(dialog_id, dialog_access_hash);
return PhotoSizeSource(DialogPhotoSmall(dialog_id, dialog_access_hash));
}
}
PhotoSizeSource(int64 sticker_set_id, int64 sticker_set_access_hash)
: variant(StickerSetThumbnail(sticker_set_id, sticker_set_access_hash)) {
static PhotoSizeSource sticker_set_thumbnail(int64 sticker_set_id, int64 sticker_set_access_hash) {
return PhotoSizeSource(StickerSetThumbnail(sticker_set_id, sticker_set_access_hash));
}
PhotoSizeSource(std::nullptr_t, int64 volume_id, int32 local_id, int64 secret)
: variant(FullLegacy(volume_id, local_id, secret)) {
static PhotoSizeSource full_legacy(int64 volume_id, int32 local_id, int64 secret) {
return PhotoSizeSource(FullLegacy(volume_id, local_id, secret));
}
PhotoSizeSource(DialogId dialog_id, int64 dialog_access_hash, bool is_big, int64 volume_id, int32 local_id) {
static PhotoSizeSource dialog_photo_legacy(DialogId dialog_id, int64 dialog_access_hash, bool is_big, int64 volume_id,
int32 local_id) {
if (is_big) {
variant = DialogPhotoBigLegacy(dialog_id, dialog_access_hash, volume_id, local_id);
return PhotoSizeSource(DialogPhotoBigLegacy(dialog_id, dialog_access_hash, volume_id, local_id));
} else {
variant = DialogPhotoSmallLegacy(dialog_id, dialog_access_hash, volume_id, local_id);
return PhotoSizeSource(DialogPhotoSmallLegacy(dialog_id, dialog_access_hash, volume_id, local_id));
}
}
PhotoSizeSource(int64 sticker_set_id, int64 sticker_set_access_hash, int64 volume_id, int32 local_id)
: variant(StickerSetThumbnailLegacy(sticker_set_id, sticker_set_access_hash, volume_id, local_id)) {
static PhotoSizeSource sticker_set_thumbnail_legacy(int64 sticker_set_id, int64 sticker_set_access_hash,
int64 volume_id, int32 local_id) {
return PhotoSizeSource(StickerSetThumbnailLegacy(sticker_set_id, sticker_set_access_hash, volume_id, local_id));
}
PhotoSizeSource(int64 sticker_set_id, int64 sticker_set_access_hash, int32 version)
: variant(StickerSetThumbnailVersion(sticker_set_id, sticker_set_access_hash, version)) {
static PhotoSizeSource sticker_set_thumbnail(int64 sticker_set_id, int64 sticker_set_access_hash, int32 version) {
return PhotoSizeSource(StickerSetThumbnailVersion(sticker_set_id, sticker_set_access_hash, version));
}
Type get_type() const {
auto offset = variant.get_offset();
auto offset = variant_.get_offset();
CHECK(offset >= 0);
return static_cast<Type>(offset);
}
@ -179,58 +186,58 @@ struct PhotoSizeSource {
FileType get_file_type() const;
Thumbnail &thumbnail() {
return variant.get<Thumbnail>();
return variant_.get<Thumbnail>();
}
const Legacy &legacy() const {
return variant.get<Legacy>();
return variant_.get<Legacy>();
}
const Thumbnail &thumbnail() const {
return variant.get<Thumbnail>();
return variant_.get<Thumbnail>();
}
const DialogPhoto &dialog_photo() const {
switch (variant.get_offset()) {
switch (variant_.get_offset()) {
case 2:
return variant.get<DialogPhotoSmall>();
return variant_.get<DialogPhotoSmall>();
case 3:
return variant.get<DialogPhotoBig>();
return variant_.get<DialogPhotoBig>();
case 6:
return variant.get<DialogPhotoSmallLegacy>();
return variant_.get<DialogPhotoSmallLegacy>();
case 7:
return variant.get<DialogPhotoBigLegacy>();
return variant_.get<DialogPhotoBigLegacy>();
default:
UNREACHABLE();
return variant.get<DialogPhotoSmall>();
return variant_.get<DialogPhotoSmall>();
}
}
const StickerSetThumbnail &sticker_set_thumbnail() const {
switch (variant.get_offset()) {
switch (variant_.get_offset()) {
case 4:
return variant.get<StickerSetThumbnail>();
return variant_.get<StickerSetThumbnail>();
case 8:
return variant.get<StickerSetThumbnailLegacy>();
return variant_.get<StickerSetThumbnailLegacy>();
case 9:
return variant.get<StickerSetThumbnailVersion>();
return variant_.get<StickerSetThumbnailVersion>();
default:
UNREACHABLE();
return variant.get<StickerSetThumbnail>();
return variant_.get<StickerSetThumbnail>();
}
}
const FullLegacy &full_legacy() const {
return variant.get<FullLegacy>();
return variant_.get<FullLegacy>();
}
const DialogPhotoLegacy &dialog_photo_legacy() const {
if (variant.get_offset() == 6) {
return variant.get<DialogPhotoSmallLegacy>();
if (variant_.get_offset() == 6) {
return variant_.get<DialogPhotoSmallLegacy>();
} else {
return variant.get<DialogPhotoBigLegacy>();
return variant_.get<DialogPhotoBigLegacy>();
}
}
const StickerSetThumbnailLegacy &sticker_set_thumbnail_legacy() const {
return variant.get<StickerSetThumbnailLegacy>();
return variant_.get<StickerSetThumbnailLegacy>();
}
const StickerSetThumbnailVersion &sticker_set_thumbnail_version() const {
return variant.get<StickerSetThumbnailVersion>();
return variant_.get<StickerSetThumbnailVersion>();
}
// returns unique representation of the source
@ -249,7 +256,11 @@ struct PhotoSizeSource {
private:
Variant<Legacy, Thumbnail, DialogPhotoSmall, DialogPhotoBig, StickerSetThumbnail, FullLegacy, DialogPhotoSmallLegacy,
DialogPhotoBigLegacy, StickerSetThumbnailLegacy, StickerSetThumbnailVersion>
variant;
variant_;
template <class T>
explicit PhotoSizeSource(const T &variant) : variant_(variant) {
}
};
bool operator==(const PhotoSizeSource &lhs, const PhotoSizeSource &rhs);

View File

@ -180,12 +180,12 @@ void parse(PhotoSizeSource::StickerSetThumbnailVersion &source, ParserT &parser)
template <class StorerT>
void PhotoSizeSource::store(StorerT &storer) const {
td::store(variant, storer);
td::store(variant_, storer);
}
template <class ParserT>
void PhotoSizeSource::parse(ParserT &parser) {
td::parse(variant, parser);
td::parse(variant_, parser);
}
} // namespace td

View File

@ -1491,7 +1491,7 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptr<telegram_api::poll
}
CHECK(poll_results != nullptr);
bool is_min = (poll_results->flags_ & telegram_api::pollResults::MIN_MASK) != 0;
bool is_min = poll_results->min_;
bool has_total_voters = (poll_results->flags_ & telegram_api::pollResults::TOTAL_VOTERS_MASK) != 0;
if (has_total_voters && poll_results->total_voters_ != poll->total_voter_count) {
poll->total_voter_count = poll_results->total_voters_;
@ -1510,14 +1510,14 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptr<telegram_api::poll
continue;
}
if (!is_min) {
bool is_chosen = (poll_result->flags_ & telegram_api::pollAnswerVoters::CHOSEN_MASK) != 0;
bool is_chosen = poll_result->chosen_;
if (is_chosen != option.is_chosen) {
option.is_chosen = is_chosen;
is_changed = true;
}
}
if (!is_min || poll_server_is_closed) {
bool is_correct = (poll_result->flags_ & telegram_api::pollAnswerVoters::CORRECT_MASK) != 0;
bool is_correct = poll_result->correct_;
if (is_correct) {
if (correct_option_id != -1) {
LOG(ERROR) << "Receive more than 1 correct answers " << correct_option_id << " and " << option_index;

View File

@ -6,9 +6,6 @@
//
#include "td/telegram/PrivacyManager.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/ChannelId.h"
#include "td/telegram/ChatId.h"
#include "td/telegram/ContactsManager.h"

View File

@ -8,12 +8,10 @@
#include "td/telegram/net/DcId.h"
#include "td/telegram/net/NetQueryCreator.h"
#include "td/telegram/SecretChatId.h"
#include "td/telegram/ServerMessageId.h"
#include "td/telegram/UniqueId.h"
#include "td/telegram/secret_api.hpp"
#include "td/telegram/ServerMessageId.h"
#include "td/telegram/telegram_api.hpp"
#include "td/telegram/UniqueId.h"
#include "td/mtproto/PacketInfo.h"
#include "td/mtproto/PacketStorer.h"
@ -693,7 +691,7 @@ void SecretChatActor::do_close_chat_impl(bool delete_history, bool is_already_di
context_->secret_chat_db()->erase_value(pfs_state_);
context_->secret_chat_db()->erase_value(seq_no_state_);
MultiPromiseActorSafe mpas{"DeleteMessagesFromServerMultiPromiseActor"};
MultiPromiseActorSafe mpas{"CloseSecretChatMultiPromiseActor"};
mpas.add_promise(
PromiseCreator::lambda([actor_id = actor_id(this), log_event_id, promise = std::move(promise)](Unit) mutable {
send_closure(actor_id, &SecretChatActor::on_closed, log_event_id, std::move(promise));

View File

@ -9,10 +9,9 @@
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/SecureStorage.h"
#include "td/telegram/SecureValue.h"
#include "td/telegram/UserId.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/UserId.h"
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"

View File

@ -15,9 +15,6 @@
#include "td/telegram/misc.h"
#include "td/telegram/net/DcId.h"
#include "td/telegram/Payments.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/telegram_api.hpp"
#include "td/utils/algorithm.h"
@ -245,10 +242,9 @@ SuitableSecureValue get_suitable_secure_value(
const tl_object_ptr<telegram_api::secureRequiredType> &secure_required_type) {
SuitableSecureValue result;
result.type = get_secure_value_type(secure_required_type->type_);
auto flags = secure_required_type->flags_;
result.is_selfie_required = (flags & telegram_api::secureRequiredType::SELFIE_REQUIRED_MASK) != 0;
result.is_translation_required = (flags & telegram_api::secureRequiredType::TRANSLATION_REQUIRED_MASK) != 0;
result.is_native_name_required = (flags & telegram_api::secureRequiredType::NATIVE_NAMES_MASK) != 0;
result.is_selfie_required = secure_required_type->selfie_required_;
result.is_translation_required = secure_required_type->translation_required_;
result.is_native_name_required = secure_required_type->native_names_;
return result;
}

View File

@ -6,11 +6,10 @@
//
#pragma once
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/files/FileId.h"
#include "td/telegram/SecureStorage.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/common.h"
#include "td/utils/optional.h"

View File

@ -7,18 +7,21 @@
#include "td/telegram/SponsoredMessageManager.h"
#include "td/telegram/ChannelId.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/Global.h"
#include "td/telegram/MessageContent.h"
#include "td/telegram/MessageEntity.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/net/NetQueryCreator.h"
#include "td/telegram/ServerMessageId.h"
#include "td/telegram/Td.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/algorithm.h"
#include "td/utils/buffer.h"
#include "td/utils/logging.h"
#include "td/utils/SliceBuilder.h"
#include "td/utils/Status.h"
#include <limits>
@ -95,13 +98,16 @@ class ViewSponsoredMessageQuery final : public Td::ResultHandler {
struct SponsoredMessageManager::SponsoredMessage {
int32 local_id = 0;
DialogId sponsor_dialog_id;
ServerMessageId server_message_id;
string start_param;
unique_ptr<MessageContent> content;
SponsoredMessage() = default;
SponsoredMessage(int32 local_id, DialogId sponsor_dialog_id, string start_param, unique_ptr<MessageContent> content)
SponsoredMessage(int32 local_id, DialogId sponsor_dialog_id, ServerMessageId server_message_id, string start_param,
unique_ptr<MessageContent> content)
: local_id(local_id)
, sponsor_dialog_id(sponsor_dialog_id)
, server_message_id(server_message_id)
, start_param(std::move(start_param))
, content(std::move(content)) {
}
@ -162,6 +168,13 @@ td_api::object_ptr<td_api::sponsoredMessage> SponsoredMessageManager::get_sponso
link = td_api::make_object<td_api::internalLinkTypeBotStart>(bot_username, sponsored_message.start_param);
break;
}
case DialogType::Channel: {
auto channel_id = sponsored_message.sponsor_dialog_id.get_channel_id();
auto t_me = G()->shared_config().get_option_string("t_me_url", "https://t.me/");
link = td_api::make_object<td_api::internalLinkTypeMessage>(
PSTRING() << t_me << "/c" << channel_id.get() << '/' << sponsored_message.server_message_id.get());
break;
}
default:
break;
}
@ -239,22 +252,30 @@ void SponsoredMessageManager::on_get_dialog_sponsored_messages(
LOG(ERROR) << "Receive unknown sponsor " << sponsor_dialog_id;
continue;
}
auto server_message_id = ServerMessageId(sponsored_message->channel_post_);
if (!server_message_id.is_valid() && server_message_id != ServerMessageId()) {
LOG(ERROR) << "Receive invalid channel post in " << to_string(sponsored_message);
server_message_id = ServerMessageId();
}
td_->messages_manager_->force_create_dialog(sponsor_dialog_id, "on_get_dialog_sponsored_messages");
auto message_text = get_message_text(td_->contacts_manager_.get(), std::move(sponsored_message->message_),
std::move(sponsored_message->entities_), true, true, 0, false,
"on_get_dialog_sponsored_messages");
int32 ttl = 0;
auto content = get_message_content(td_, std::move(message_text), nullptr, sponsor_dialog_id, true, UserId(), &ttl);
bool disable_web_page_preview = false;
auto content = get_message_content(td_, std::move(message_text), nullptr, sponsor_dialog_id, true, UserId(), &ttl,
&disable_web_page_preview);
if (ttl != 0) {
LOG(ERROR) << "Receive sponsored message with TTL " << ttl;
continue;
}
CHECK(disable_web_page_preview);
CHECK(current_sponsored_message_id_ < std::numeric_limits<int32>::max());
auto local_id = ++current_sponsored_message_id_;
messages->message_random_ids[local_id] = sponsored_message->random_id_.as_slice().str();
messages->messages.emplace_back(local_id, sponsor_dialog_id, std::move(sponsored_message->start_param_),
std::move(content));
messages->messages.emplace_back(local_id, sponsor_dialog_id, server_message_id,
std::move(sponsored_message->start_param_), std::move(content));
}
for (auto &promise : promises) {

View File

@ -25,6 +25,8 @@
#include "td/telegram/misc.h"
#include "td/telegram/net/DcId.h"
#include "td/telegram/net/MtprotoHeader.h"
#include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/PhotoSizeSource.h"
#include "td/telegram/secret_api.h"
#include "td/telegram/StickerSetId.hpp"
#include "td/telegram/StickersManager.hpp"
@ -42,10 +44,12 @@
#include "td/actor/SleepActor.h"
#include "td/utils/algorithm.h"
#include "td/utils/base64.h"
#include "td/utils/emoji.h"
#include "td/utils/format.h"
#include "td/utils/JsonBuilder.h"
#include "td/utils/logging.h"
#include "td/utils/MimeType.h"
#include "td/utils/misc.h"
#include "td/utils/PathView.h"
#include "td/utils/Random.h"
@ -1231,11 +1235,12 @@ class StickersManager::UploadStickerFileCallback final : public FileManager::Upl
StickersManager::StickersManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
upload_sticker_file_callback_ = std::make_shared<UploadStickerFileCallback>();
on_update_animated_emoji_zoom();
on_update_recent_stickers_limit(
narrow_cast<int32>(G()->shared_config().get_option_integer("recent_stickers_limit", 200)));
on_update_favorite_stickers_limit(
narrow_cast<int32>(G()->shared_config().get_option_integer("favorite_stickers_limit", 5)));
on_update_dice_emojis();
next_click_animated_emoji_message_time_ = Time::now();
next_update_animated_emoji_clicked_time_ = Time::now();
@ -1280,6 +1285,13 @@ void StickersManager::init() {
on_update_dice_success_values();
on_update_emoji_sounds();
on_update_disable_animated_emojis();
if (!disable_animated_emojis_) {
load_special_sticker_set(add_special_sticker_set(SpecialStickerSetType::animated_emoji()));
}
if (G()->parameters().use_file_db) {
auto old_featured_sticker_set_count_str = G()->td_db()->get_binlog_pmc()->get("old_featured_sticker_set_count");
if (!old_featured_sticker_set_count_str.empty()) {
@ -1358,10 +1370,12 @@ void StickersManager::load_special_sticker_set_by_type(const SpecialStickerSetTy
}
void StickersManager::load_special_sticker_set(SpecialStickerSet &sticker_set) {
CHECK(!td_->auth_manager_->is_bot());
if (sticker_set.is_being_loaded_) {
return;
}
sticker_set.is_being_loaded_ = true;
LOG(INFO) << "Load " << sticker_set.type_.type_ << " " << sticker_set.id_;
if (sticker_set.id_.is_valid()) {
auto promise = PromiseCreator::lambda([actor_id = actor_id(this), type = sticker_set.type_](Result<Unit> &&result) {
send_closure(actor_id, &StickersManager::on_load_special_sticker_set, type,
@ -1399,6 +1413,15 @@ void StickersManager::on_load_special_sticker_set(const SpecialStickerSetType &t
special_sticker_set.is_being_loaded_ = false;
if (type.type_ == SpecialStickerSetType::animated_emoji()) {
auto promises = std::move(pending_get_animated_emoji_queries_);
reset_to_empty(pending_get_animated_emoji_queries_);
for (auto &promise : promises) {
promise.set_value(Unit());
}
return;
}
CHECK(special_sticker_set.id_.is_valid());
auto sticker_set = get_sticker_set(special_sticker_set.id_);
CHECK(sticker_set != nullptr);
@ -1459,7 +1482,7 @@ tl_object_ptr<td_api::MaskPoint> StickersManager::get_mask_point_object(int32 po
}
vector<td_api::object_ptr<td_api::closedVectorPath>> StickersManager::get_sticker_minithumbnail(
CSlice path, StickerSetId sticker_set_id, int64 document_id) {
CSlice path, StickerSetId sticker_set_id, int64 document_id, double zoom) {
if (path.empty()) {
return {};
}
@ -1514,8 +1537,8 @@ vector<td_api::object_ptr<td_api::closedVectorPath>> StickersManager::get_sticke
}
return sign * res;
};
auto make_point = [](double x, double y) {
return td_api::make_object<td_api::point>(x, y);
auto make_point = [zoom](double x, double y) {
return td_api::make_object<td_api::point>(x * zoom, y * zoom);
};
vector<td_api::object_ptr<td_api::closedVectorPath>> result;
@ -1696,7 +1719,8 @@ vector<td_api::object_ptr<td_api::closedVectorPath>> StickersManager::get_sticke
return result;
}
tl_object_ptr<td_api::sticker> StickersManager::get_sticker_object(FileId file_id) const {
tl_object_ptr<td_api::sticker> StickersManager::get_sticker_object(FileId file_id, bool for_animated_emoji,
bool for_clicked_animated_emoji) const {
if (!file_id.is_valid()) {
return nullptr;
}
@ -1732,11 +1756,18 @@ tl_object_ptr<td_api::sticker> StickersManager::get_sticker_object(FileId file_i
}
}
auto thumbnail_object = get_thumbnail_object(td_->file_manager_.get(), thumbnail, thumbnail_format);
int32 width = sticker->dimensions.width;
int32 height = sticker->dimensions.height;
double zoom = 1.0;
if (sticker->is_animated && (for_animated_emoji || for_clicked_animated_emoji)) {
zoom = for_clicked_animated_emoji ? 3 * animated_emoji_zoom_ : animated_emoji_zoom_;
width = static_cast<int32>(width * zoom + 0.5);
height = static_cast<int32>(height * zoom + 0.5);
}
return make_tl_object<td_api::sticker>(
sticker->set_id.get(), sticker->dimensions.width, sticker->dimensions.height, sticker->alt, sticker->is_animated,
sticker->is_mask, std::move(mask_position),
get_sticker_minithumbnail(sticker->minithumbnail, sticker->set_id, document_id), std::move(thumbnail_object),
td_->file_manager_->get_file_object(file_id));
sticker->set_id.get(), width, height, sticker->alt, sticker->is_animated, sticker->is_mask,
std::move(mask_position), get_sticker_minithumbnail(sticker->minithumbnail, sticker->set_id, document_id, zoom),
std::move(thumbnail_object), td_->file_manager_->get_file_object(file_id));
}
tl_object_ptr<td_api::stickers> StickersManager::get_stickers_object(const vector<FileId> &sticker_ids) const {
@ -1773,7 +1804,7 @@ tl_object_ptr<td_api::DiceStickers> StickersManager::get_dice_stickers_object(co
}
auto get_sticker = [&](int32 value) {
return get_sticker_object(sticker_set->sticker_ids[value]);
return get_sticker_object(sticker_set->sticker_ids[value], true);
};
if (emoji == "🎰") {
@ -1840,7 +1871,7 @@ tl_object_ptr<td_api::stickerSet> StickersManager::get_sticker_set_object(Sticke
sticker_set->is_animated ? PhotoFormat::Tgs : PhotoFormat::Webp);
return make_tl_object<td_api::stickerSet>(
sticker_set->id.get(), sticker_set->title, sticker_set->short_name, std::move(thumbnail),
get_sticker_minithumbnail(sticker_set->minithumbnail, sticker_set->id, -2),
get_sticker_minithumbnail(sticker_set->minithumbnail, sticker_set->id, -2, 1.0),
sticker_set->is_installed && !sticker_set->is_archived, sticker_set->is_archived, sticker_set->is_official,
sticker_set->is_animated, sticker_set->is_masks, sticker_set->is_viewed, std::move(stickers), std::move(emojis));
}
@ -1886,13 +1917,127 @@ tl_object_ptr<td_api::stickerSetInfo> StickersManager::get_sticker_set_info_obje
sticker_set->is_animated ? PhotoFormat::Tgs : PhotoFormat::Webp);
return make_tl_object<td_api::stickerSetInfo>(
sticker_set->id.get(), sticker_set->title, sticker_set->short_name, std::move(thumbnail),
get_sticker_minithumbnail(sticker_set->minithumbnail, sticker_set->id, -3),
get_sticker_minithumbnail(sticker_set->minithumbnail, sticker_set->id, -3, 1.0),
sticker_set->is_installed && !sticker_set->is_archived, sticker_set->is_archived, sticker_set->is_official,
sticker_set->is_animated, sticker_set->is_masks, sticker_set->is_viewed,
sticker_set->was_loaded ? narrow_cast<int32>(sticker_set->sticker_ids.size()) : sticker_set->sticker_count,
std::move(stickers));
}
const StickersManager::StickerSet *StickersManager::get_animated_emoji_sticker_set() {
if (td_->auth_manager_->is_bot() || disable_animated_emojis_) {
return nullptr;
}
auto &special_sticker_set = add_special_sticker_set(SpecialStickerSetType::animated_emoji());
if (!special_sticker_set.id_.is_valid()) {
load_special_sticker_set(special_sticker_set);
return nullptr;
}
auto sticker_set = get_sticker_set(special_sticker_set.id_);
CHECK(sticker_set != nullptr);
if (!sticker_set->was_loaded) {
load_special_sticker_set(special_sticker_set);
return nullptr;
}
return sticker_set;
}
std::pair<FileId, int> StickersManager::get_animated_emoji_sticker(const StickerSet *sticker_set, const string &emoji) {
if (sticker_set == nullptr) {
return {};
}
auto emoji_without_modifiers = remove_emoji_modifiers(emoji).str();
auto it = sticker_set->emoji_stickers_map_.find(emoji_without_modifiers);
if (it == sticker_set->emoji_stickers_map_.end()) {
return {};
}
// trying to find full emoji match
for (const auto &sticker_id : it->second) {
auto emoji_it = sticker_set->sticker_emojis_map_.find(sticker_id);
CHECK(emoji_it != sticker_set->sticker_emojis_map_.end());
if (td::contains(emoji_it->second, emoji)) {
return {sticker_id, 0};
}
}
// trying to find match without Fitzpatrick modifiers
int modifier_id = get_fitzpatrick_modifier(emoji);
if (modifier_id > 0) {
for (const auto &sticker_id : it->second) {
auto emoji_it = sticker_set->sticker_emojis_map_.find(sticker_id);
CHECK(emoji_it != sticker_set->sticker_emojis_map_.end());
if (td::contains(emoji_it->second, Slice(emoji).remove_suffix(4))) {
return {sticker_id, modifier_id};
}
}
}
// there is no match
return {};
}
std::pair<FileId, int> StickersManager::get_animated_emoji_sticker(const string &emoji) {
return get_animated_emoji_sticker(get_animated_emoji_sticker_set(), emoji);
}
FileId StickersManager::get_animated_emoji_sound_file_id(const string &emoji) const {
auto it = emoji_sounds_.find(remove_fitzpatrick_modifier(emoji).str());
if (it == emoji_sounds_.end()) {
return {};
}
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) {
auto it = emoji_messages_.find(emoji);
if (it == emoji_messages_.end()) {
return get_animated_emoji_object(get_animated_emoji_sticker(emoji), get_animated_emoji_sound_file_id(emoji));
} else {
return get_animated_emoji_object(it->second.animated_emoji_sticker, it->second.sound_file_id);
}
}
td_api::object_ptr<td_api::animatedEmoji> StickersManager::get_animated_emoji_object(
std::pair<FileId, int> animated_sticker, FileId sound_file_id) const {
if (!animated_sticker.first.is_valid()) {
return nullptr;
}
return td_api::make_object<td_api::animatedEmoji>(
get_sticker_object(animated_sticker.first, true), get_color_replacements_object(animated_sticker.second),
sound_file_id.is_valid() ? td_->file_manager_->get_file_object(sound_file_id) : nullptr);
}
tl_object_ptr<telegram_api::InputStickerSet> StickersManager::get_input_sticker_set(StickerSetId sticker_set_id) const {
auto sticker_set = get_sticker_set(sticker_set_id);
if (sticker_set == nullptr) {
@ -2021,9 +2166,9 @@ std::pair<int64, FileId> StickersManager::on_get_sticker_document(
string minithumbnail;
auto thumbnail_format = has_webp_thumbnail(document->thumbs_) ? PhotoFormat::Webp : PhotoFormat::Jpeg;
for (auto &thumb : document->thumbs_) {
auto photo_size = get_photo_size(td_->file_manager_.get(), {FileType::Thumbnail, 0}, document_id,
document->access_hash_, document->file_reference_.as_slice().str(), dc_id,
DialogId(), std::move(thumb), thumbnail_format);
auto photo_size = get_photo_size(td_->file_manager_.get(), PhotoSizeSource::thumbnail(FileType::Thumbnail, 0),
document_id, document->access_hash_, document->file_reference_.as_slice().str(),
dc_id, DialogId(), std::move(thumb), thumbnail_format);
if (photo_size.get_offset() == 0) {
if (!thumbnail.file_id.is_valid()) {
thumbnail = std::move(photo_size.get<0>());
@ -2547,17 +2692,19 @@ StickerSetId StickersManager::on_get_sticker_set(tl_object_ptr<telegram_api::sti
StickerSet *s = add_sticker_set(set_id, set->access_hash_);
bool is_installed = (set->flags_ & telegram_api::stickerSet::INSTALLED_DATE_MASK) != 0;
bool is_archived = (set->flags_ & telegram_api::stickerSet::ARCHIVED_MASK) != 0;
bool is_official = (set->flags_ & telegram_api::stickerSet::OFFICIAL_MASK) != 0;
bool is_animated = (set->flags_ & telegram_api::stickerSet::ANIMATED_MASK) != 0;
bool is_masks = (set->flags_ & telegram_api::stickerSet::MASKS_MASK) != 0;
bool is_archived = set->archived_;
bool is_official = set->official_;
bool is_animated = set->animated_;
bool is_masks = set->masks_;
PhotoSize thumbnail;
string minithumbnail;
for (auto &thumb : set->thumbs_) {
auto photo_size = get_photo_size(td_->file_manager_.get(), {set_id.get(), s->access_hash, set->thumb_version_}, 0,
0, "", DcId::create(set->thumb_dc_id_), DialogId(), std::move(thumb),
is_animated ? PhotoFormat::Tgs : PhotoFormat::Webp);
auto photo_size =
get_photo_size(td_->file_manager_.get(),
PhotoSizeSource::sticker_set_thumbnail(set_id.get(), s->access_hash, set->thumb_version_), 0, 0,
"", DcId::create(set->thumb_dc_id_), DialogId(), std::move(thumb),
is_animated ? PhotoFormat::Tgs : PhotoFormat::Webp);
if (photo_size.get_offset() == 0) {
if (!thumbnail.file_id.is_valid()) {
thumbnail = std::move(photo_size.get<0>());
@ -2807,6 +2954,11 @@ StickerSetId StickersManager::on_get_messages_sticker_set(StickerSetId sticker_s
update_sticker_set(s);
update_load_requests(s, true, Status::OK());
send_update_installed_sticker_sets();
if (set_id == add_special_sticker_set(SpecialStickerSetType::animated_emoji()).id_) {
try_update_animated_emoji_messages();
}
return set_id;
}
@ -2864,14 +3016,6 @@ void StickersManager::on_get_special_sticker_set(const SpecialStickerSetType &ty
CHECK(s->is_inited);
CHECK(s->is_loaded);
/*
if (type.type_ == SpecialStickerSetType::animated_emoji_click()) {
for (auto &sticker_id : s->sticker_ids) {
// TODO get supported emoji and their numbers
}
}
*/
LOG(INFO) << "Receive special sticker set " << type.type_ << ": " << sticker_set_id << ' ' << s->access_hash << ' '
<< s->short_name;
auto &sticker_set = add_special_sticker_set(type.type_);
@ -2890,6 +3034,7 @@ void StickersManager::on_get_special_sticker_set(const SpecialStickerSetType &ty
<< ' ' << sticker_set.short_name_);
if (type.type_ == SpecialStickerSetType::animated_emoji()) {
G()->shared_config().set_option_string(PSLICE() << type.type_ << "_name", sticker_set.short_name_);
try_update_animated_emoji_messages();
} else if (!type.get_dice_emoji().empty()) {
sticker_set.is_being_loaded_ = true;
}
@ -3959,6 +4104,66 @@ void StickersManager::on_update_dice_success_values() {
});
}
void StickersManager::on_update_emoji_sounds() {
if (G()->close_flag() || !is_inited_ || td_->auth_manager_->is_bot()) {
return;
}
auto emoji_sounds_str = G()->shared_config().get_option_string("emoji_sounds");
if (emoji_sounds_str == emoji_sounds_str_) {
return;
}
LOG(INFO) << "Change emoji sounds to " << emoji_sounds_str;
emoji_sounds_str_ = std::move(emoji_sounds_str);
vector<FileId> old_file_ids;
for (auto &emoji_sound : emoji_sounds_) {
old_file_ids.push_back(emoji_sound.second);
}
emoji_sounds_.clear();
vector<FileId> new_file_ids;
auto sounds = full_split(Slice(emoji_sounds_str_), ',');
CHECK(sounds.size() % 2 == 0);
for (size_t i = 0; i < sounds.size(); i += 2) {
vector<Slice> parts = full_split(sounds[i + 1], ':');
CHECK(parts.size() == 3);
auto id = to_integer<int64>(parts[0]);
auto access_hash = to_integer<int64>(parts[1]);
auto dc_id = G()->net_query_dispatcher().get_main_dc_id();
auto file_reference = base64url_decode(parts[2]).move_as_ok();
int32 expected_size = 7000;
auto suggested_file_name = PSTRING() << static_cast<uint64>(id) << '.'
<< MimeType::to_extension("audio/ogg", "oga");
auto file_id = td_->file_manager_->register_remote(
FullRemoteFileLocation(FileType::VoiceNote, id, access_hash, dc_id, std::move(file_reference)),
FileLocationSource::FromServer, DialogId(), 0, expected_size, std::move(suggested_file_name));
CHECK(file_id.is_valid());
emoji_sounds_.emplace(remove_fitzpatrick_modifier(sounds[i]).str(), file_id);
new_file_ids.push_back(file_id);
}
td_->file_manager_->change_files_source(get_app_config_file_source_id(), old_file_ids, new_file_ids);
try_update_animated_emoji_messages();
}
void StickersManager::on_update_disable_animated_emojis() {
if (G()->close_flag() || !is_inited_ || td_->auth_manager_->is_bot()) {
return;
}
auto disable_animated_emojis = G()->shared_config().get_option_boolean("disable_animated_emoji");
if (disable_animated_emojis == disable_animated_emojis_) {
return;
}
disable_animated_emojis_ = disable_animated_emojis;
if (!disable_animated_emojis_) {
load_special_sticker_set(add_special_sticker_set(SpecialStickerSetType::animated_emoji()));
}
try_update_animated_emoji_messages();
}
void StickersManager::on_update_sticker_sets() {
// TODO better support
archived_sticker_set_ids_[0].clear();
@ -3970,6 +4175,26 @@ void StickersManager::on_update_sticker_sets() {
reload_installed_sticker_sets(true, true);
}
void StickersManager::try_update_animated_emoji_messages() {
auto sticker_set = get_animated_emoji_sticker_set();
vector<FullMessageId> full_message_ids;
for (auto &it : emoji_messages_) {
auto new_animated_sticker = get_animated_emoji_sticker(sticker_set, it.first);
auto new_sound_file_id = get_animated_emoji_sound_file_id(it.first);
if (new_animated_sticker != it.second.animated_emoji_sticker ||
(new_animated_sticker.first.is_valid() && new_sound_file_id != it.second.sound_file_id)) {
it.second.animated_emoji_sticker = new_animated_sticker;
it.second.sound_file_id = new_sound_file_id;
for (auto full_message_id : it.second.full_message_ids) {
full_message_ids.push_back(full_message_id);
}
}
}
for (auto full_message_id : full_message_ids) {
td_->messages_manager_->on_external_update_message_content(full_message_id);
}
}
void StickersManager::register_dice(const string &emoji, int32 value, FullMessageId full_message_id,
const char *source) {
CHECK(!emoji.empty());
@ -3985,8 +4210,7 @@ void StickersManager::register_dice(const string &emoji, int32 value, FullMessag
if (!td::contains(dice_emojis_, emoji)) {
if (full_message_id.get_message_id().is_any_server() &&
full_message_id.get_dialog_id().get_type() != DialogType::SecretChat) {
send_closure(G()->config_manager(), &ConfigManager::get_app_config,
Promise<td_api::object_ptr<td_api::JsonValue>>());
send_closure(G()->config_manager(), &ConfigManager::reget_app_config, Promise<Unit>());
}
return;
}
@ -4028,8 +4252,74 @@ void StickersManager::unregister_dice(const string &emoji, int32 value, FullMess
}
}
void StickersManager::register_emoji(const string &emoji, FullMessageId full_message_id, const char *source) {
CHECK(!emoji.empty());
if (td_->auth_manager_->is_bot()) {
return;
}
LOG(INFO) << "Register emoji " << emoji << " from " << full_message_id << " from " << source;
auto &emoji_messages = emoji_messages_[emoji];
if (emoji_messages.full_message_ids.empty()) {
emoji_messages.animated_emoji_sticker = get_animated_emoji_sticker(emoji);
emoji_messages.sound_file_id = get_animated_emoji_sound_file_id(emoji);
}
bool is_inserted = emoji_messages.full_message_ids.insert(full_message_id).second;
LOG_CHECK(is_inserted) << source << ' ' << emoji << ' ' << full_message_id;
}
void StickersManager::unregister_emoji(const string &emoji, FullMessageId full_message_id, const char *source) {
CHECK(!emoji.empty());
if (td_->auth_manager_->is_bot()) {
return;
}
LOG(INFO) << "Unregister emoji " << emoji << " from " << full_message_id << " from " << source;
auto it = emoji_messages_.find(emoji);
CHECK(it != emoji_messages_.end());
auto &full_message_ids = it->second.full_message_ids;
auto is_deleted = full_message_ids.erase(full_message_id) > 0;
LOG_CHECK(is_deleted) << source << ' ' << emoji << ' ' << full_message_id;
if (full_message_ids.empty()) {
emoji_messages_.erase(it);
}
}
void StickersManager::get_animated_emoji(string emoji, bool is_recursive,
Promise<td_api::object_ptr<td_api::animatedEmoji>> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
auto &special_sticker_set = add_special_sticker_set(SpecialStickerSetType::animated_emoji());
auto sticker_set = get_sticker_set(special_sticker_set.id_);
if (sticker_set == nullptr || !sticker_set->was_loaded) {
if (is_recursive) {
return promise.set_value(nullptr);
}
pending_get_animated_emoji_queries_.push_back(
PromiseCreator::lambda([actor_id = actor_id(this), emoji = std::move(emoji),
promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
send_closure(actor_id, &StickersManager::get_animated_emoji, std::move(emoji), true, std::move(promise));
}
}));
load_special_sticker_set(special_sticker_set);
return;
}
promise.set_value(get_animated_emoji_object(get_animated_emoji_sticker(sticker_set, emoji),
get_animated_emoji_sound_file_id(emoji)));
}
void StickersManager::get_animated_emoji_click_sticker(const string &message_text, FullMessageId full_message_id,
Promise<td_api::object_ptr<td_api::sticker>> &&promise) {
if (disable_animated_emojis_ || td_->auth_manager_->is_bot()) {
return promise.set_value(nullptr);
}
auto &special_sticker_set = add_special_sticker_set(SpecialStickerSetType::animated_emoji_click());
if (!special_sticker_set.id_.is_valid()) {
// don't wait for the first load of the sticker set from the server
@ -4064,7 +4354,7 @@ int StickersManager::get_emoji_number(Slice emoji) {
return emoji[0] - '0';
}
vector<FileId> StickersManager::get_animated_emoji_stickers(const StickerSet *sticker_set, Slice emoji) const {
vector<FileId> StickersManager::get_animated_emoji_click_stickers(const StickerSet *sticker_set, Slice emoji) const {
vector<FileId> result;
for (auto sticker_id : sticker_set->sticker_ids) {
auto s = get_sticker(sticker_id);
@ -4076,7 +4366,7 @@ vector<FileId> StickersManager::get_animated_emoji_stickers(const StickerSet *st
if (result.empty()) {
const static vector<string> heart_emojis{"💛", "💙", "💚", "💜", "🧡", "🖤", "🤎", "🤍"};
if (td::contains(heart_emojis, emoji)) {
return get_animated_emoji_stickers(sticker_set, Slice(""));
return get_animated_emoji_click_stickers(sticker_set, Slice(""));
}
}
return result;
@ -4091,13 +4381,17 @@ void StickersManager::choose_animated_emoji_click_sticker(const StickerSet *stic
return promise.set_error(Status::Error(400, "Message is not an animated emoji message"));
}
if (disable_animated_emojis_ || td_->auth_manager_->is_bot()) {
return promise.set_value(nullptr);
}
auto now = Time::now();
if (last_clicked_animated_emoji_ == message_text && last_clicked_animated_emoji_full_message_id_ == full_message_id &&
next_click_animated_emoji_message_time_ >= now + 2 * MIN_ANIMATED_EMOJI_CLICK_DELAY) {
return promise.set_value(nullptr);
}
auto all_sticker_ids = get_animated_emoji_stickers(sticker_set, message_text);
auto all_sticker_ids = get_animated_emoji_click_stickers(sticker_set, message_text);
vector<std::pair<int, FileId>> found_stickers;
for (auto sticker_id : all_sticker_ids) {
auto it = sticker_set->sticker_emojis_map_.find(sticker_id);
@ -4143,7 +4437,7 @@ void StickersManager::choose_animated_emoji_click_sticker(const StickerSet *stic
}
if (now >= next_click_animated_emoji_message_time_) {
next_click_animated_emoji_message_time_ = now + MIN_ANIMATED_EMOJI_CLICK_DELAY;
promise.set_value(get_sticker_object(result.second));
promise.set_value(get_sticker_object(result.second, false, true));
} else {
create_actor<SleepActor>("SendClickAnimatedEmojiMessageResponse", next_click_animated_emoji_message_time_ - now,
PromiseCreator::lambda([actor_id = actor_id(this), sticker_id = result.second,
@ -4159,7 +4453,7 @@ void StickersManager::choose_animated_emoji_click_sticker(const StickerSet *stic
void StickersManager::send_click_animated_emoji_message_response(
FileId sticker_id, Promise<td_api::object_ptr<td_api::sticker>> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
promise.set_value(get_sticker_object(sticker_id));
promise.set_value(get_sticker_object(sticker_id, false, true));
}
void StickersManager::timeout_expired() {
@ -4247,6 +4541,10 @@ bool StickersManager::is_sent_animated_emoji_click(DialogId dialog_id, Slice emo
}
Status StickersManager::on_animated_emoji_message_clicked(Slice emoji, FullMessageId full_message_id, string data) {
if (td_->auth_manager_->is_bot() || disable_animated_emojis_) {
return Status::OK();
}
TRY_RESULT(value, json_decode(data));
if (value.type() != JsonValue::Type::Object) {
return Status::Error("Expected an object");
@ -4327,7 +4625,7 @@ void StickersManager::schedule_update_animated_emoji_clicked(const StickerSet *s
return;
}
auto all_sticker_ids = get_animated_emoji_stickers(sticker_set, emoji);
auto all_sticker_ids = get_animated_emoji_click_stickers(sticker_set, emoji);
std::unordered_map<int, FileId> sticker_ids;
for (auto sticker_id : all_sticker_ids) {
auto it = sticker_set->sticker_emojis_map_.find(sticker_id);
@ -4361,7 +4659,7 @@ void StickersManager::schedule_update_animated_emoji_clicked(const StickerSet *s
}
void StickersManager::send_update_animated_emoji_clicked(FullMessageId full_message_id, FileId sticker_id) {
if (G()->close_flag()) {
if (G()->close_flag() || disable_animated_emojis_ || td_->auth_manager_->is_bot()) {
return;
}
if (td_->messages_manager_->is_message_edited_recently(full_message_id, 2)) {
@ -4373,9 +4671,10 @@ void StickersManager::send_update_animated_emoji_clicked(FullMessageId full_mess
return;
}
send_closure(G()->td(), &Td::send_update,
td_api::make_object<td_api::updateAnimatedEmojiMessageClicked>(
dialog_id.get(), full_message_id.get_message_id().get(), get_sticker_object(sticker_id)));
send_closure(
G()->td(), &Td::send_update,
td_api::make_object<td_api::updateAnimatedEmojiMessageClicked>(
dialog_id.get(), full_message_id.get_message_id().get(), get_sticker_object(sticker_id, false, true)));
}
void StickersManager::view_featured_sticker_sets(const vector<StickerSetId> &sticker_set_ids) {
@ -6188,6 +6487,11 @@ void StickersManager::save_recent_stickers_to_database(bool is_attached) {
}
}
void StickersManager::on_update_animated_emoji_zoom() {
animated_emoji_zoom_ =
static_cast<double>(G()->shared_config().get_option_integer("animated_emoji_zoom", 625000000)) * 1e-9;
}
void StickersManager::on_update_recent_stickers_limit(int32 recent_stickers_limit) {
if (recent_stickers_limit != recent_stickers_limit_) {
if (recent_stickers_limit > 0) {
@ -6378,6 +6682,13 @@ int64 StickersManager::get_favorite_stickers_hash() const {
return get_recent_stickers_hash(favorite_sticker_ids_);
}
FileSourceId StickersManager::get_app_config_file_source_id() {
if (!app_config_file_source_id_.is_valid()) {
app_config_file_source_id_ = td_->file_reference_manager_->create_app_config_file_source();
}
return app_config_file_source_id_;
}
FileSourceId StickersManager::get_favorite_stickers_file_source_id() {
if (!favorite_stickers_file_source_id_.is_valid()) {
favorite_stickers_file_source_id_ = td_->file_reference_manager_->create_favorite_stickers_file_source();

View File

@ -51,7 +51,8 @@ class StickersManager final : public Actor {
void init();
tl_object_ptr<td_api::sticker> get_sticker_object(FileId file_id) const;
tl_object_ptr<td_api::sticker> get_sticker_object(FileId file_id, bool for_animated_emoji = false,
bool for_clicked_animated_emoji = false) const;
tl_object_ptr<td_api::stickers> get_stickers_object(const vector<FileId> &sticker_ids) const;
@ -65,12 +66,21 @@ class StickersManager final : public Actor {
const vector<StickerSetId> &sticker_set_ids,
size_t covers_limit) const;
td_api::object_ptr<td_api::animatedEmoji> get_animated_emoji_object(const string &emoji);
tl_object_ptr<telegram_api::InputStickerSet> get_input_sticker_set(StickerSetId sticker_set_id) const;
void register_dice(const string &emoji, int32 value, FullMessageId full_message_id, const char *source);
void unregister_dice(const string &emoji, int32 value, FullMessageId full_message_id, const char *source);
void register_emoji(const string &emoji, FullMessageId full_message_id, const char *source);
void unregister_emoji(const string &emoji, FullMessageId full_message_id, const char *source);
void get_animated_emoji(string emoji, bool is_recursive,
Promise<td_api::object_ptr<td_api::animatedEmoji>> &&promise);
void get_animated_emoji_click_sticker(const string &message_text, FullMessageId full_message_id,
Promise<td_api::object_ptr<td_api::sticker>> &&promise);
@ -144,10 +154,16 @@ class StickersManager final : public Actor {
void on_uninstall_sticker_set(StickerSetId set_id);
void on_update_animated_emoji_zoom();
void on_update_disable_animated_emojis();
void on_update_dice_emojis();
void on_update_dice_success_values();
void on_update_emoji_sounds();
void on_update_sticker_sets();
void on_update_sticker_sets_order(bool is_masks, const vector<StickerSetId> &sticker_set_ids);
@ -233,6 +249,8 @@ class StickersManager final : public Actor {
void on_get_favorite_stickers_failed(bool is_repair, Status error);
FileSourceId get_app_config_file_source_id();
FileSourceId get_favorite_stickers_file_source_id();
vector<FileId> get_favorite_stickers(Promise<Unit> &&promise);
@ -429,7 +447,7 @@ class StickersManager final : public Actor {
static vector<td_api::object_ptr<td_api::closedVectorPath>> get_sticker_minithumbnail(CSlice path,
StickerSetId sticker_set_id,
int64 document_id);
int64 document_id, double zoom);
static tl_object_ptr<td_api::MaskPoint> get_mask_point_object(int32 point);
@ -597,9 +615,24 @@ class StickersManager final : public Actor {
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();
static std::pair<FileId, int> get_animated_emoji_sticker(const StickerSet *sticker_set, const string &emoji);
std::pair<FileId, int> get_animated_emoji_sticker(const string &emoji);
FileId get_animated_emoji_sound_file_id(const string &emoji) const;
td_api::object_ptr<td_api::animatedEmoji> get_animated_emoji_object(std::pair<FileId, int> animated_sticker,
FileId sound_file_id) const;
void try_update_animated_emoji_messages();
static int get_emoji_number(Slice emoji);
vector<FileId> get_animated_emoji_stickers(const StickerSet *sticker_set, Slice emoji) const;
vector<FileId> get_animated_emoji_click_stickers(const StickerSet *sticker_set, Slice emoji) const;
void choose_animated_emoji_click_sticker(const StickerSet *sticker_set, Slice message_text,
FullMessageId full_message_id, double start_time,
@ -727,6 +760,8 @@ class StickersManager final : public Actor {
vector<FileId> favorite_sticker_file_ids_;
FileSourceId favorite_stickers_file_source_id_;
FileSourceId app_config_file_source_id_;
vector<StickerSetId> archived_sticker_set_ids_[2];
int32 total_archived_sticker_set_count_[2] = {-1, -1};
@ -768,6 +803,8 @@ class StickersManager final : public Actor {
std::unordered_map<int64, unique_ptr<PendingSetStickerSetThumbnail>> pending_set_sticker_set_thumbnails_;
vector<Promise<Unit>> pending_get_animated_emoji_queries_;
double next_click_animated_emoji_message_time_ = 0;
double next_update_animated_emoji_clicked_time_ = 0;
vector<PendingGetAnimatedEmojiClickSticker> pending_get_animated_emoji_click_stickers_;
@ -798,11 +835,25 @@ class StickersManager final : public Actor {
std::unordered_map<string, std::unordered_set<FullMessageId, FullMessageIdHash>> dice_messages_;
struct EmojiMessages {
std::unordered_set<FullMessageId, FullMessageIdHash> full_message_ids;
std::pair<FileId, int> animated_emoji_sticker;
FileId sound_file_id;
};
std::unordered_map<string, EmojiMessages> emoji_messages_;
string dice_emojis_str_;
vector<string> dice_emojis_;
string dice_success_values_str_;
vector<std::pair<int32, int32>> dice_success_values_;
string emoji_sounds_str_;
std::unordered_map<string, FileId> emoji_sounds_;
double animated_emoji_zoom_ = 0.0;
bool disable_animated_emojis_ = false;
};
} // namespace td

View File

@ -131,6 +131,7 @@
#include "td/utils/MimeType.h"
#include "td/utils/misc.h"
#include "td/utils/PathView.h"
#include "td/utils/port/Clocks.h"
#include "td/utils/port/IPAddress.h"
#include "td/utils/port/path.h"
#include "td/utils/port/SocketFd.h"
@ -1350,6 +1351,35 @@ class GetMessageThreadHistoryRequest final : public RequestActor<> {
}
};
class GetChatMessageCalendarRequest final : public RequestActor<> {
DialogId dialog_id_;
MessageId from_message_id_;
MessageSearchFilter filter_;
int64 random_id_;
td_api::object_ptr<td_api::messageCalendar> calendar_;
void do_run(Promise<Unit> &&promise) final {
calendar_ = td->messages_manager_->get_dialog_message_calendar(dialog_id_, from_message_id_, filter_, random_id_,
get_tries() == 3, std::move(promise));
}
void do_send_result() final {
send_result(std::move(calendar_));
}
public:
GetChatMessageCalendarRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, int64 from_message_id,
tl_object_ptr<td_api::SearchMessagesFilter> filter)
: RequestActor(std::move(td), request_id)
, dialog_id_(dialog_id)
, from_message_id_(from_message_id)
, filter_(get_message_search_filter(filter))
, random_id_(0) {
set_tries(3);
}
};
class SearchChatMessagesRequest final : public RequestActor<> {
DialogId dialog_id_;
string query_;
@ -2874,7 +2904,7 @@ void Td::on_get_promo_data(Result<telegram_api::object_ptr<telegram_api::help_Pr
case telegram_api::help_promoData::ID: {
auto promo = telegram_api::move_object_as<telegram_api::help_promoData>(promo_data_ptr);
expires_at = promo->expires_;
bool is_proxy = (promo->flags_ & telegram_api::help_promoData::PROXY_MASK) != 0;
bool is_proxy = promo->proxy_;
messages_manager_->on_get_sponsored_dialog(
std::move(promo->peer_),
is_proxy ? DialogSource::mtproto_proxy()
@ -3267,7 +3297,8 @@ void Td::on_result(NetQueryPtr query) {
bool Td::is_internal_config_option(Slice name) {
switch (name[0]) {
case 'a':
return name == "animation_search_emojis" || name == "animation_search_provider" || name == "auth";
return name == "animated_emoji_zoom" || name == "animation_search_emojis" ||
name == "animation_search_provider" || name == "auth";
case 'b':
return name == "base_language_pack_version";
case 'c':
@ -3277,7 +3308,7 @@ bool Td::is_internal_config_option(Slice name) {
case 'd':
return name == "dc_txt_domain_name" || name == "dice_emojis" || name == "dice_success_values";
case 'e':
return name == "edit_time_limit";
return name == "edit_time_limit" || name == "emoji_sounds";
case 'i':
return name == "ignored_restriction_reasons";
case 'l':
@ -3317,12 +3348,17 @@ void Td::on_config_option_updated(const string &name) {
return animations_manager_->on_update_animation_search_emojis(G()->shared_config().get_option_string(name));
} else if (name == "animation_search_provider") {
return animations_manager_->on_update_animation_search_provider(G()->shared_config().get_option_string(name));
} else if (name == "animated_emoji_zoom") {
// update animated emoji zoom only at launch
return;
} else if (name == "recent_stickers_limit") {
return stickers_manager_->on_update_recent_stickers_limit(
narrow_cast<int32>(G()->shared_config().get_option_integer(name)));
} else if (name == "favorite_stickers_limit") {
stickers_manager_->on_update_favorite_stickers_limit(
narrow_cast<int32>(G()->shared_config().get_option_integer(name)));
} else if (name == "disable_animated_emoji") {
stickers_manager_->on_update_disable_animated_emojis();
} else if (name == "my_id") {
G()->set_my_id(G()->shared_config().get_option_integer(name));
} else if (name == "session_count") {
@ -3361,6 +3397,10 @@ void Td::on_config_option_updated(const string &name) {
return send_closure(language_pack_manager_, &LanguagePackManager::on_language_pack_version_changed, false, -1);
} else if (name == "base_language_pack_version") {
return send_closure(language_pack_manager_, &LanguagePackManager::on_language_pack_version_changed, true, -1);
} else if (name == "utc_time_offset") {
if (G()->mtproto_header().set_tz_offset(static_cast<int32>(G()->shared_config().get_option_integer(name)))) {
G()->net_query_dispatcher().update_mtproto_header();
}
} else if (name == "notification_group_count_max") {
send_closure(notification_manager_actor_, &NotificationManager::on_notification_group_count_max_changed, true);
} else if (name == "notification_group_size_max") {
@ -3377,6 +3417,8 @@ void Td::on_config_option_updated(const string &name) {
return send_closure(stickers_manager_actor_, &StickersManager::on_update_dice_emojis);
} else if (name == "dice_success_values") {
return send_closure(stickers_manager_actor_, &StickersManager::on_update_dice_success_values);
} else if (name == "emoji_sounds") {
return send_closure(stickers_manager_actor_, &StickersManager::on_update_emoji_sounds);
} else if (is_internal_config_option(name)) {
return;
}
@ -3854,6 +3896,7 @@ Status Td::init(DbKey key) {
options_.language_pack = G()->shared_config().get_option_string("localization_target");
options_.language_code = G()->shared_config().get_option_string("language_pack_id");
options_.parameters = G()->shared_config().get_option_string("connection_parameters");
options_.tz_offset = static_cast<int32>(G()->shared_config().get_option_integer("utc_time_offset"));
options_.is_emulator = G()->shared_config().get_option_boolean("is_emulator");
// options_.proxy = Proxy();
G()->set_mtproto_header(make_unique<MtprotoHeader>(options_));
@ -4010,6 +4053,7 @@ void Td::init_options_and_network() {
if (!G()->shared_config().have_option("suggested_video_note_audio_bitrate")) {
G()->shared_config().set_option_integer("suggested_video_note_audio_bitrate", 64);
}
G()->shared_config().set_option_integer("utc_time_offset", Clocks::tz_offset());
init_connection_creator();
@ -4453,9 +4497,9 @@ Status Td::set_parameters(td_api::object_ptr<td_api::tdlibParameters> parameters
options_.application_version += ", TDLib ";
options_.application_version += TDLIB_VERSION;
}
options_.language_pack = "";
options_.language_code = "";
options_.parameters = "";
options_.language_pack = string();
options_.language_code = string();
options_.parameters = string();
options_.is_emulator = false;
options_.proxy = Proxy();
@ -5354,6 +5398,11 @@ void Td::on_request(uint64 id, const td_api::getMessageThreadHistory &request) {
request.offset_, request.limit_);
}
void Td::on_request(uint64 id, td_api::getChatMessageCalendar &request) {
CHECK_IS_USER();
CREATE_REQUEST(GetChatMessageCalendarRequest, request.chat_id_, request.from_message_id_, std::move(request.filter_));
}
void Td::on_request(uint64 id, td_api::searchChatMessages &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.query_);
@ -5409,7 +5458,15 @@ void Td::on_request(uint64 id, const td_api::getChatMessageByDate &request) {
CREATE_REQUEST(GetChatMessageByDateRequest, request.chat_id_, request.date_);
}
void Td::on_request(uint64 id, td_api::getChatMessageCount &request) {
void Td::on_request(uint64 id, const td_api::getChatSparseMessagePositions &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
messages_manager_->get_dialog_sparse_message_positions(
DialogId(request.chat_id_), get_message_search_filter(request.filter_), MessageId(request.from_message_id_),
request.limit_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getChatMessageCount &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result<int32> result) mutable {
@ -5465,6 +5522,13 @@ void Td::on_request(uint64 id, const td_api::deleteChatMessagesFromUser &request
std::move(promise));
}
void Td::on_request(uint64 id, const td_api::deleteChatMessagesByDate &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
messages_manager_->delete_dialog_messages_by_date(DialogId(request.chat_id_), request.min_date_, request.max_date_,
request.revoke_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::readAllChatMentions &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
@ -5806,13 +5870,13 @@ void Td::on_request(uint64 id, td_api::sendCallDebugInformation &request) {
std::move(request.debug_information_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getVoiceChatAvailableParticipants &request) {
void Td::on_request(uint64 id, const td_api::getVideoChatAvailableParticipants &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
group_call_manager_->get_group_call_join_as(DialogId(request.chat_id_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::setVoiceChatDefaultParticipant &request) {
void Td::on_request(uint64 id, const td_api::setVideoChatDefaultParticipant &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
group_call_manager_->set_group_call_default_join_as(
@ -5820,7 +5884,7 @@ void Td::on_request(uint64 id, const td_api::setVoiceChatDefaultParticipant &req
std::move(promise));
}
void Td::on_request(uint64 id, td_api::createVoiceChat &request) {
void Td::on_request(uint64 id, td_api::createVideoChat &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.title_);
CREATE_REQUEST_PROMISE();
@ -6322,20 +6386,25 @@ void Td::on_request(uint64 id, td_api::getChatAdministrators &request) {
void Td::on_request(uint64 id, const td_api::replacePrimaryChatInviteLink &request) {
CREATE_REQUEST_PROMISE();
contacts_manager_->export_dialog_invite_link(DialogId(request.chat_id_), 0, 0, true, std::move(promise));
contacts_manager_->export_dialog_invite_link(DialogId(request.chat_id_), string(), 0, 0, false, true,
std::move(promise));
}
void Td::on_request(uint64 id, const td_api::createChatInviteLink &request) {
void Td::on_request(uint64 id, td_api::createChatInviteLink &request) {
CLEAN_INPUT_STRING(request.name_);
CREATE_REQUEST_PROMISE();
contacts_manager_->export_dialog_invite_link(DialogId(request.chat_id_), request.expire_date_, request.member_limit_,
false, std::move(promise));
contacts_manager_->export_dialog_invite_link(DialogId(request.chat_id_), std::move(request.name_),
request.expire_date_, request.member_limit_,
request.creates_join_request_, false, std::move(promise));
}
void Td::on_request(uint64 id, td_api::editChatInviteLink &request) {
CLEAN_INPUT_STRING(request.name_);
CLEAN_INPUT_STRING(request.invite_link_);
CREATE_REQUEST_PROMISE();
contacts_manager_->edit_dialog_invite_link(DialogId(request.chat_id_), request.invite_link_, request.expire_date_,
request.member_limit_, std::move(promise));
contacts_manager_->edit_dialog_invite_link(DialogId(request.chat_id_), request.invite_link_, std::move(request.name_),
request.expire_date_, request.member_limit_, request.creates_join_request_,
std::move(promise));
}
void Td::on_request(uint64 id, td_api::getChatInviteLink &request) {
@ -6369,6 +6438,27 @@ void Td::on_request(uint64 id, td_api::getChatInviteLinkMembers &request) {
std::move(promise));
}
void Td::on_request(uint64 id, td_api::getChatJoinRequests &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.invite_link_);
CLEAN_INPUT_STRING(request.query_);
CREATE_REQUEST_PROMISE();
contacts_manager_->get_dialog_join_requests(DialogId(request.chat_id_), request.invite_link_, request.query_,
std::move(request.offset_request_), request.limit_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::approveChatJoinRequest &request) {
CREATE_OK_REQUEST_PROMISE();
contacts_manager_->process_dialog_join_requests(DialogId(request.chat_id_), UserId(request.user_id_), true,
std::move(promise));
}
void Td::on_request(uint64 id, const td_api::declineChatJoinRequest &request) {
CREATE_OK_REQUEST_PROMISE();
contacts_manager_->process_dialog_join_requests(DialogId(request.chat_id_), UserId(request.user_id_), false,
std::move(promise));
}
void Td::on_request(uint64 id, td_api::revokeChatInviteLink &request) {
CLEAN_INPUT_STRING(request.invite_link_);
CREATE_REQUEST_PROMISE();
@ -6999,6 +7089,13 @@ void Td::on_request(uint64 id, td_api::searchEmojis &request) {
std::move(request.input_language_codes_));
}
void Td::on_request(uint64 id, td_api::getAnimatedEmoji &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.emoji_);
CREATE_REQUEST_PROMISE();
stickers_manager_->get_animated_emoji(std::move(request.emoji_), false, std::move(promise));
}
void Td::on_request(uint64 id, td_api::getEmojiSuggestionsUrl &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.language_code_);
@ -7246,6 +7343,14 @@ void Td::on_request(uint64 id, td_api::getOption &request) {
send_closure_later(config_manager_, &ConfigManager::get_content_settings, std::move(promise));
return;
}
if (!is_bot && request.name_ == "is_location_visible") {
auto promise = PromiseCreator::lambda([actor_id = actor_id(this), id](Result<Unit> &&result) {
// the option is already updated on success, ignore errors
send_closure(actor_id, &Td::send_result, id, G()->shared_config().get_option_value("is_location_visible"));
});
send_closure_later(contacts_manager_actor_, &ContactsManager::get_is_location_visible, std::move(promise));
return;
}
break;
case 'o':
if (request.name_ == "online") {
@ -7379,6 +7484,9 @@ void Td::on_request(uint64 id, td_api::setOption &request) {
}
break;
case 'd':
if (!is_bot && set_boolean_option("disable_animated_emoji")) {
return;
}
if (!is_bot && set_boolean_option("disable_contact_registered_notifications")) {
return;
}
@ -7560,6 +7668,20 @@ void Td::on_request(uint64 id, td_api::setOption &request) {
return;
}
break;
case 'u':
if (set_boolean_option("use_pfs")) {
return;
}
if (set_boolean_option("use_quick_ack")) {
return;
}
if (set_boolean_option("use_storage_optimizer")) {
return;
}
if (set_integer_option("utc_time_offset", -12 * 60 * 60, 14 * 60 * 60)) {
return;
}
break;
case 'X':
case 'x': {
if (request.name_.size() > 255) {
@ -7586,17 +7708,6 @@ void Td::on_request(uint64 id, td_api::setOption &request) {
}
return send_closure(actor_id(this), &Td::send_result, id, make_tl_object<td_api::ok>());
}
case 'u':
if (set_boolean_option("use_pfs")) {
return;
}
if (set_boolean_option("use_quick_ack")) {
return;
}
if (set_boolean_option("use_storage_optimizer")) {
return;
}
break;
}
return send_error_raw(id, 400, "Option can't be set");

View File

@ -253,7 +253,7 @@ class Td final : public Actor {
static td_api::object_ptr<td_api::Object> static_request(td_api::object_ptr<td_api::Function> function);
private:
static constexpr const char *TDLIB_VERSION = "1.7.8";
static constexpr const char *TDLIB_VERSION = "1.7.9";
static constexpr int64 ONLINE_ALARM_ID = 0;
static constexpr int64 PING_SERVER_ALARM_ID = -1;
static constexpr int32 PING_SERVER_TIMEOUT = 300;
@ -623,6 +623,8 @@ class Td final : public Actor {
void on_request(uint64 id, const td_api::getMessageThreadHistory &request);
void on_request(uint64 id, td_api::getChatMessageCalendar &request);
void on_request(uint64 id, td_api::searchChatMessages &request);
void on_request(uint64 id, td_api::searchSecretMessages &request);
@ -639,7 +641,9 @@ class Td final : public Actor {
void on_request(uint64 id, const td_api::getChatMessageByDate &request);
void on_request(uint64 id, td_api::getChatMessageCount &request);
void on_request(uint64 id, const td_api::getChatSparseMessagePositions &request);
void on_request(uint64 id, const td_api::getChatMessageCount &request);
void on_request(uint64 id, const td_api::getChatScheduledMessages &request);
@ -653,6 +657,8 @@ class Td final : public Actor {
void on_request(uint64 id, const td_api::deleteChatMessagesFromUser &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, td_api::sendMessage &request);
@ -735,11 +741,11 @@ class Td final : public Actor {
void on_request(uint64 id, td_api::sendCallDebugInformation &request);
void on_request(uint64 id, const td_api::getVoiceChatAvailableParticipants &request);
void on_request(uint64 id, const td_api::getVideoChatAvailableParticipants &request);
void on_request(uint64 id, const td_api::setVoiceChatDefaultParticipant &request);
void on_request(uint64 id, const td_api::setVideoChatDefaultParticipant &request);
void on_request(uint64 id, td_api::createVoiceChat &request);
void on_request(uint64 id, td_api::createVideoChat &request);
void on_request(uint64 id, const td_api::getGroupCall &request);
@ -869,7 +875,7 @@ class Td final : public Actor {
void on_request(uint64 id, const td_api::replacePrimaryChatInviteLink &request);
void on_request(uint64 id, const td_api::createChatInviteLink &request);
void on_request(uint64 id, td_api::createChatInviteLink &request);
void on_request(uint64 id, td_api::editChatInviteLink &request);
@ -881,6 +887,12 @@ class Td final : public Actor {
void on_request(uint64 id, td_api::getChatInviteLinkMembers &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::declineChatJoinRequest &request);
void on_request(uint64 id, td_api::revokeChatInviteLink &request);
void on_request(uint64 id, td_api::deleteRevokedChatInviteLink &request);
@ -1043,6 +1055,8 @@ class Td final : public Actor {
void on_request(uint64 id, td_api::searchEmojis &request);
void on_request(uint64 id, td_api::getAnimatedEmoji &request);
void on_request(uint64 id, td_api::getEmojiSuggestionsUrl &request);
void on_request(uint64 id, const td_api::getFavoriteStickers &request);

View File

@ -91,14 +91,14 @@ Status init_binlog(Binlog &binlog, string path, BinlogKeyValue<Binlog> &binlog_p
break;
case LogEvent::HandlerType::SendMessage:
case LogEvent::HandlerType::DeleteMessage:
case LogEvent::HandlerType::DeleteMessagesFromServer:
case LogEvent::HandlerType::DeleteMessagesOnServer:
case LogEvent::HandlerType::ReadHistoryOnServer:
case LogEvent::HandlerType::ReadMessageContentsOnServer:
case LogEvent::HandlerType::ForwardMessages:
case LogEvent::HandlerType::SendBotStartMessage:
case LogEvent::HandlerType::SendScreenshotTakenNotificationMessage:
case LogEvent::HandlerType::SendInlineQueryResultMessage:
case LogEvent::HandlerType::DeleteDialogHistoryFromServer:
case LogEvent::HandlerType::DeleteDialogHistoryOnServer:
case LogEvent::HandlerType::ReadAllDialogMentionsOnServer:
case LogEvent::HandlerType::DeleteAllChannelMessagesFromUserOnServer:
case LogEvent::HandlerType::ToggleDialogIsPinnedOnServer:
@ -108,17 +108,18 @@ Status init_binlog(Binlog &binlog, string path, BinlogKeyValue<Binlog> &binlog_p
case LogEvent::HandlerType::UpdateScopeNotificationSettingsOnServer:
case LogEvent::HandlerType::ResetAllNotificationSettingsOnServer:
case LogEvent::HandlerType::ToggleDialogReportSpamStateOnServer:
case LogEvent::HandlerType::GetDialogFromServer:
case LogEvent::HandlerType::RegetDialog:
case LogEvent::HandlerType::GetChannelDifference:
case LogEvent::HandlerType::ReadHistoryInSecretChat:
case LogEvent::HandlerType::ToggleDialogIsMarkedAsUnreadOnServer:
case LogEvent::HandlerType::SetDialogFolderIdOnServer:
case LogEvent::HandlerType::DeleteScheduledMessagesFromServer:
case LogEvent::HandlerType::DeleteScheduledMessagesOnServer:
case LogEvent::HandlerType::ToggleDialogIsBlockedOnServer:
case LogEvent::HandlerType::ReadMessageThreadHistoryOnServer:
case LogEvent::HandlerType::BlockMessageSenderFromRepliesOnServer:
case LogEvent::HandlerType::UnpinAllDialogMessagesOnServer:
case LogEvent::HandlerType::DeleteAllCallMessagesFromServer:
case LogEvent::HandlerType::DeleteAllCallMessagesOnServer:
case LogEvent::HandlerType::DeleteDialogMessagesByDateOnServer:
events.to_messages_manager.push_back(event.clone());
break;
case LogEvent::HandlerType::AddMessagePushNotification:

View File

@ -106,9 +106,8 @@ TermsOfService::TermsOfService(telegram_api::object_ptr<telegram_api::help_terms
id_.clear();
}
text_ = FormattedText{std::move(terms->text_), std::move(entities)};
min_user_age_ =
((terms->flags_ & telegram_api::help_termsOfService::MIN_AGE_CONFIRM_MASK) != 0 ? terms->min_age_confirm_ : 0);
show_popup_ = (terms->flags_ & telegram_api::help_termsOfService::POPUP_MASK) != 0;
min_user_age_ = terms->min_age_confirm_;
show_popup_ = terms->popup_;
}
void get_terms_of_service(Td *td, Promise<std::pair<int32, TermsOfService>> promise) {

View File

@ -6,11 +6,10 @@
//
#pragma once
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/MessageEntity.h"
#include "td/telegram/MessageEntity.hpp"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/actor/PromiseFuture.h"

View File

@ -16,6 +16,7 @@
#include "td/utils/algorithm.h"
#include "td/utils/buffer.h"
#include "td/utils/emoji.h"
#include "td/utils/logging.h"
#include "td/utils/Random.h"
#include "td/utils/Time.h"
@ -24,14 +25,14 @@
namespace td {
class GetChatThemesQuery final : public Td::ResultHandler {
Promise<telegram_api::object_ptr<telegram_api::account_ChatThemes>> promise_;
Promise<telegram_api::object_ptr<telegram_api::account_Themes>> promise_;
public:
explicit GetChatThemesQuery(Promise<telegram_api::object_ptr<telegram_api::account_ChatThemes>> &&promise)
explicit GetChatThemesQuery(Promise<telegram_api::object_ptr<telegram_api::account_Themes>> &&promise)
: promise_(std::move(promise)) {
}
void send(int32 hash) {
void send(int64 hash) {
send_query(G()->net_query_creator().create(telegram_api::account_getChatThemes(hash)));
}
@ -111,8 +112,7 @@ void ThemeManager::ChatTheme::store(StorerT &storer) const {
BEGIN_STORE_FLAGS();
END_STORE_FLAGS();
td::store(emoji, storer);
td::store(light_id, storer);
td::store(dark_id, storer);
td::store(id, storer);
td::store(light_theme, storer);
td::store(dark_theme, storer);
}
@ -122,8 +122,7 @@ void ThemeManager::ChatTheme::parse(ParserT &parser) {
BEGIN_PARSE_FLAGS();
END_PARSE_FLAGS();
td::parse(emoji, parser);
td::parse(light_id, parser);
td::parse(dark_id, parser);
td::parse(id, parser);
td::parse(light_theme, parser);
td::parse(dark_theme, parser);
}
@ -180,29 +179,57 @@ void ThemeManager::loop() {
}
auto request_promise = PromiseCreator::lambda(
[actor_id = actor_id(this)](Result<telegram_api::object_ptr<telegram_api::account_ChatThemes>> result) {
[actor_id = actor_id(this)](Result<telegram_api::object_ptr<telegram_api::account_Themes>> result) {
send_closure(actor_id, &ThemeManager::on_get_chat_themes, std::move(result));
});
td_->create_handler<GetChatThemesQuery>(std::move(request_promise))->send(chat_themes_.hash);
}
bool ThemeManager::is_dark_base_theme(BaseTheme base_theme) {
switch (base_theme) {
case BaseTheme::Classic:
case BaseTheme::Day:
case BaseTheme::Arctic:
return false;
case BaseTheme::Night:
case BaseTheme::Tinted:
return true;
default:
UNREACHABLE();
return false;
}
}
void ThemeManager::on_update_theme(telegram_api::object_ptr<telegram_api::theme> &&theme, Promise<Unit> &&promise) {
CHECK(theme != nullptr);
bool is_changed = false;
bool was_light = false;
bool was_dark = false;
for (auto &chat_theme : chat_themes_.themes) {
if (chat_theme.light_id == theme->id_ || chat_theme.dark_id == theme->id_) {
auto theme_settings = get_chat_theme_settings(std::move(theme->settings_));
if (theme_settings.message_colors.empty()) {
break;
}
if (chat_theme.light_id == theme->id_ && chat_theme.light_theme != theme_settings) {
chat_theme.light_theme = theme_settings;
is_changed = true;
}
if (chat_theme.dark_id == theme->id_ && chat_theme.dark_theme != theme_settings) {
chat_theme.dark_theme = theme_settings;
is_changed = true;
if (chat_theme.id == theme->id_) {
for (auto &settings : theme->settings_) {
auto theme_settings = get_chat_theme_settings(std::move(settings));
if (theme_settings.message_colors.empty()) {
continue;
}
if (is_dark_base_theme(theme_settings.base_theme)) {
if (!was_dark) {
was_dark = true;
if (chat_theme.dark_theme != theme_settings) {
chat_theme.dark_theme = std::move(theme_settings);
is_changed = true;
}
}
} else {
if (!was_light) {
was_light = true;
if (chat_theme.light_theme != theme_settings) {
chat_theme.light_theme = std::move(theme_settings);
is_changed = true;
}
}
}
}
}
}
@ -254,7 +281,7 @@ void ThemeManager::send_update_chat_themes() const {
send_closure(G()->td(), &Td::send_update, get_update_chat_themes_object());
}
void ThemeManager::on_get_chat_themes(Result<telegram_api::object_ptr<telegram_api::account_ChatThemes>> result) {
void ThemeManager::on_get_chat_themes(Result<telegram_api::object_ptr<telegram_api::account_Themes>> result) {
if (result.is_error()) {
set_timeout_in(Random::fast(40, 60));
return;
@ -265,29 +292,49 @@ void ThemeManager::on_get_chat_themes(Result<telegram_api::object_ptr<telegram_a
auto chat_themes_ptr = result.move_as_ok();
LOG(DEBUG) << "Receive " << to_string(chat_themes_ptr);
if (chat_themes_ptr->get_id() == telegram_api::account_chatThemesNotModified::ID) {
if (chat_themes_ptr->get_id() == telegram_api::account_themesNotModified::ID) {
return;
}
CHECK(chat_themes_ptr->get_id() == telegram_api::account_chatThemes::ID);
auto chat_themes = telegram_api::move_object_as<telegram_api::account_chatThemes>(chat_themes_ptr);
CHECK(chat_themes_ptr->get_id() == telegram_api::account_themes::ID);
auto chat_themes = telegram_api::move_object_as<telegram_api::account_themes>(chat_themes_ptr);
chat_themes_.hash = chat_themes->hash_;
chat_themes_.themes.clear();
for (auto &chat_theme : chat_themes->themes_) {
if (chat_theme->emoticon_.empty()) {
LOG(ERROR) << "Receive " << to_string(chat_theme);
for (auto &theme : chat_themes->themes_) {
if (!is_emoji(theme->emoticon_) || !theme->for_chat_) {
LOG(ERROR) << "Receive " << to_string(theme);
continue;
}
ChatTheme theme;
theme.emoji = std::move(chat_theme->emoticon_);
theme.light_id = chat_theme->theme_->id_;
theme.dark_id = chat_theme->dark_theme_->id_;
theme.light_theme = get_chat_theme_settings(std::move(chat_theme->theme_->settings_));
theme.dark_theme = get_chat_theme_settings(std::move(chat_theme->dark_theme_->settings_));
if (theme.light_theme.message_colors.empty() || theme.dark_theme.message_colors.empty()) {
bool was_light = false;
bool was_dark = false;
ChatTheme chat_theme;
chat_theme.emoji = std::move(theme->emoticon_);
chat_theme.id = theme->id_;
for (auto &settings : theme->settings_) {
auto theme_settings = get_chat_theme_settings(std::move(settings));
if (theme_settings.message_colors.empty()) {
continue;
}
if (is_dark_base_theme(theme_settings.base_theme)) {
if (!was_dark) {
was_dark = true;
if (chat_theme.dark_theme != theme_settings) {
chat_theme.dark_theme = std::move(theme_settings);
}
}
} else {
if (!was_light) {
was_light = true;
if (chat_theme.light_theme != theme_settings) {
chat_theme.light_theme = std::move(theme_settings);
}
}
}
}
if (chat_theme.light_theme.message_colors.empty() || chat_theme.dark_theme.message_colors.empty()) {
continue;
}
chat_themes_.themes.push_back(std::move(theme));
chat_themes_.themes.push_back(std::move(chat_theme));
}
save_chat_themes();

View File

@ -59,8 +59,7 @@ class ThemeManager final : public Actor {
struct ChatTheme {
string emoji;
int64 light_id = 0;
int64 dark_id = 0;
int64 id = 0;
ThemeSettings light_theme;
ThemeSettings dark_theme;
@ -72,7 +71,7 @@ class ThemeManager final : public Actor {
};
struct ChatThemes {
int32 hash = 0;
int64 hash = 0;
double next_reload_time = 0;
vector<ChatTheme> themes;
@ -89,7 +88,9 @@ class ThemeManager final : public Actor {
void tear_down() final;
void on_get_chat_themes(Result<telegram_api::object_ptr<telegram_api::account_ChatThemes>> result);
static bool is_dark_base_theme(BaseTheme base_theme);
void on_get_chat_themes(Result<telegram_api::object_ptr<telegram_api::account_Themes>> result);
td_api::object_ptr<td_api::themeSettings> get_theme_settings_object(const ThemeSettings &settings) const;

View File

@ -56,6 +56,7 @@ TopDialogCategory get_top_dialog_category(const td_api::object_ptr<td_api::TopCh
return TopDialogCategory::Size;
}
}
TopDialogCategory get_top_dialog_category(const telegram_api::object_ptr<telegram_api::TopPeerCategory> &category) {
CHECK(category != nullptr);
switch (category->get_id()) {

View File

@ -6,9 +6,6 @@
//
#include "td/telegram/UpdatesManager.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.hpp"
#include "td/telegram/AnimationsManager.h"
#include "td/telegram/AuthManager.h"
#include "td/telegram/CallbackQueriesManager.h"
@ -46,7 +43,9 @@
#include "td/telegram/StickerSetId.h"
#include "td/telegram/StickersManager.h"
#include "td/telegram/Td.h"
#include "td/telegram/td_api.h"
#include "td/telegram/TdDb.h"
#include "td/telegram/telegram_api.hpp"
#include "td/telegram/ThemeManager.h"
#include "td/telegram/WebPagesManager.h"
@ -177,6 +176,28 @@ void UpdatesManager::tear_down() {
parent_.reset();
}
void UpdatesManager::hangup_shared() {
ref_cnt_--;
if (ref_cnt_ == 0) {
stop();
}
}
void UpdatesManager::hangup() {
pending_pts_updates_.clear();
postponed_pts_updates_.clear();
postponed_updates_.clear();
pending_seq_updates_.clear();
pending_qts_updates_.clear();
hangup_shared();
}
ActorShared<UpdatesManager> UpdatesManager::create_reference() {
ref_cnt_++;
return actor_shared(this, 1);
}
void UpdatesManager::fill_pts_gap(void *td) {
CHECK(td != nullptr);
if (G()->close_flag()) {
@ -676,6 +697,7 @@ bool UpdatesManager::is_acceptable_message(const telegram_api::Message *message_
case telegram_api::messageActionGroupCallScheduled::ID:
case telegram_api::messageActionSetMessagesTTL::ID:
case telegram_api::messageActionSetChatTheme::ID:
case telegram_api::messageActionChatJoinedByRequest::ID:
break;
case telegram_api::messageActionChatCreate::ID: {
auto chat_create = static_cast<const telegram_api::messageActionChatCreate *>(action);
@ -695,13 +717,9 @@ bool UpdatesManager::is_acceptable_message(const telegram_api::Message *message_
}
break;
}
case telegram_api::messageActionChatJoinedByLink::ID: {
auto chat_joined_by_link = static_cast<const telegram_api::messageActionChatJoinedByLink *>(action);
if (!is_acceptable_user(UserId(chat_joined_by_link->inviter_id_))) {
return false;
}
case telegram_api::messageActionChatJoinedByLink::ID:
// inviter_id_ isn't used
break;
}
case telegram_api::messageActionChatDeleteUser::ID: {
auto chat_delete_user = static_cast<const telegram_api::messageActionChatDeleteUser *>(action);
if (!is_acceptable_user(UserId(chat_delete_user->user_id_))) {
@ -1656,7 +1674,7 @@ void UpdatesManager::on_pending_updates(vector<tl_object_ptr<telegram_api::Updat
}
MultiPromiseActorSafe mpas{"OnPendingUpdatesMultiPromiseActor"};
mpas.add_promise([actor_id = actor_id(this), promise = std::move(promise)](Result<Unit> &&result) mutable {
mpas.add_promise([actor_id = create_reference(), promise = std::move(promise)](Result<Unit> &&result) mutable {
send_closure(actor_id, &UpdatesManager::on_pending_updates_processed, std::move(result), std::move(promise));
});
auto lock = mpas.get_promise();
@ -1777,7 +1795,7 @@ void UpdatesManager::on_pending_updates(vector<tl_object_ptr<telegram_api::Updat
lock.set_value(Unit());
}
void UpdatesManager::on_pending_updates_processed(Result<Unit> &&result, Promise<Unit> &&promise) {
void UpdatesManager::on_pending_updates_processed(Result<Unit> result, Promise<Unit> promise) {
promise.set_result(std::move(result));
}
@ -2123,6 +2141,14 @@ void UpdatesManager::process_qts_update(tl_object_ptr<telegram_api::Update> &&up
add_qts(qts).set_value(Unit());
break;
}
case telegram_api::updateBotChatInviteRequester::ID: {
auto update = move_tl_object_as<telegram_api::updateBotChatInviteRequester>(update_ptr);
td_->contacts_manager_->on_update_chat_invite_requester(DialogId(update->peer_), UserId(update->user_id_),
std::move(update->about_), update->date_,
DialogInviteLink(std::move(update->invite_)));
add_qts(qts).set_value(Unit());
break;
}
default:
UNREACHABLE();
break;
@ -2778,6 +2804,7 @@ bool UpdatesManager::is_qts_update(const telegram_api::Update *update) {
case telegram_api::updateBotStopped::ID:
case telegram_api::updateChatParticipant::ID:
case telegram_api::updateChannelParticipant::ID:
case telegram_api::updateBotChatInviteRequester::ID:
return true;
default:
return false;
@ -2796,6 +2823,8 @@ int32 UpdatesManager::get_update_qts(const telegram_api::Update *update) {
return static_cast<const telegram_api::updateChatParticipant *>(update)->qts_;
case telegram_api::updateChannelParticipant::ID:
return static_cast<const telegram_api::updateChannelParticipant *>(update)->qts_;
case telegram_api::updateBotChatInviteRequester::ID:
return static_cast<const telegram_api::updateBotChatInviteRequester *>(update)->qts_;
default:
return 0;
}
@ -2921,9 +2950,8 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateDraftMessage> u
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateDialogPinned> update, Promise<Unit> &&promise) {
FolderId folder_id(update->flags_ & telegram_api::updateDialogPinned::FOLDER_ID_MASK ? update->folder_id_ : 0);
td_->messages_manager_->on_update_dialog_is_pinned(
folder_id, DialogId(update->peer_), (update->flags_ & telegram_api::updateDialogPinned::PINNED_MASK) != 0);
td_->messages_manager_->on_update_dialog_is_pinned(FolderId(update->folder_id_), DialogId(update->peer_),
update->pinned_);
promise.set_value(Unit());
}
@ -2934,8 +2962,7 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updatePinnedDialogs>
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateDialogUnreadMark> update, Promise<Unit> &&promise) {
td_->messages_manager_->on_update_dialog_is_marked_as_unread(
DialogId(update->peer_), (update->flags_ & telegram_api::updateDialogUnreadMark::UNREAD_MASK) != 0);
td_->messages_manager_->on_update_dialog_is_marked_as_unread(DialogId(update->peer_), update->unread_);
promise.set_value(Unit());
}
@ -3040,8 +3067,7 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateStickerSets> up
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateStickerSetsOrder> update, Promise<Unit> &&promise) {
bool is_masks = (update->flags_ & telegram_api::updateStickerSetsOrder::MASKS_MASK) != 0;
td_->stickers_manager_->on_update_sticker_sets_order(is_masks,
td_->stickers_manager_->on_update_sticker_sets_order(update->masks_,
StickersManager::convert_sticker_set_ids(update->order_));
promise.set_value(Unit());
}
@ -3211,10 +3237,22 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannelParticip
add_pending_qts_update(std::move(update), qts, std::move(promise));
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateBotChatInviteRequester> update,
Promise<Unit> &&promise) {
auto qts = update->qts_;
add_pending_qts_update(std::move(update), qts, std::move(promise));
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateTheme> update, Promise<Unit> &&promise) {
td_->theme_manager_->on_update_theme(std::move(update->theme_), std::move(promise));
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updatePendingJoinRequests> update, Promise<Unit> &&promise) {
td_->messages_manager_->on_update_dialog_pending_join_requests(DialogId(update->peer_), update->requests_pending_,
std::move(update->recent_requesters_));
promise.set_value(Unit());
}
// unsupported updates
} // namespace td

View File

@ -23,6 +23,7 @@
#include "td/utils/logging.h"
#include "td/utils/Status.h"
#include "td/utils/tl_storers.h"
#include "td/utils/TlStorerToString.h"
#include <map>
#include <unordered_set>
@ -180,6 +181,7 @@ class UpdatesManager final : public Actor {
Td *td_;
ActorShared<> parent_;
int32 ref_cnt_ = 1;
PtsManager pts_manager_;
PtsManager qts_manager_;
@ -224,6 +226,12 @@ class UpdatesManager final : public Actor {
void tear_down() final;
void hangup_shared() final;
void hangup() final;
ActorShared<UpdatesManager> create_reference();
int32 get_pts() const {
return pts_manager_.mem_pts();
}
@ -267,7 +275,7 @@ class UpdatesManager final : public Actor {
void on_pending_updates(vector<tl_object_ptr<telegram_api::Update>> &&updates, int32 seq_begin, int32 seq_end,
int32 date, double receive_time, Promise<Unit> &&promise, const char *source);
void on_pending_updates_processed(Result<Unit> &&result, Promise<Unit> &&promise);
void on_pending_updates_processed(Result<Unit> result, Promise<Unit> promise);
void process_updates(vector<tl_object_ptr<telegram_api::Update>> &&updates, bool force_apply,
Promise<Unit> &&promise);
@ -487,9 +495,12 @@ class UpdatesManager final : public Actor {
void on_update(tl_object_ptr<telegram_api::updateBotStopped> update, Promise<Unit> &&promise);
void on_update(tl_object_ptr<telegram_api::updateChatParticipant> update, Promise<Unit> &&promise);
void on_update(tl_object_ptr<telegram_api::updateChannelParticipant> update, Promise<Unit> &&promise);
void on_update(tl_object_ptr<telegram_api::updateBotChatInviteRequester> update, Promise<Unit> &&promise);
void on_update(tl_object_ptr<telegram_api::updateTheme> update, Promise<Unit> &&promise);
void on_update(tl_object_ptr<telegram_api::updatePendingJoinRequests> update, Promise<Unit> &&promise);
// unsupported updates
};

View File

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

View File

@ -6,12 +6,11 @@
//
#pragma once
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/files/FileId.h"
#include "td/telegram/Photo.h"
#include "td/telegram/SecretInputMedia.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/buffer.h"
#include "td/utils/common.h"

View File

@ -6,12 +6,11 @@
//
#pragma once
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/files/FileId.h"
#include "td/telegram/Photo.h"
#include "td/telegram/SecretInputMedia.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/buffer.h"
#include "td/utils/common.h"

View File

@ -6,11 +6,10 @@
//
#pragma once
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/files/FileId.h"
#include "td/telegram/SecretInputMedia.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/common.h"

View File

@ -2039,8 +2039,8 @@ unique_ptr<WebPageBlock> get_web_page_block(Td *td, tl_object_ptr<telegram_api::
}
case telegram_api::pageBlockVideo::ID: {
auto page_block = move_tl_object_as<telegram_api::pageBlockVideo>(page_block_ptr);
bool need_autoplay = (page_block->flags_ & telegram_api::pageBlockVideo::AUTOPLAY_MASK) != 0;
bool is_looped = (page_block->flags_ & telegram_api::pageBlockVideo::LOOP_MASK) != 0;
bool need_autoplay = page_block->autoplay_;
bool is_looped = page_block->loop_;
auto animations_it = animations.find(page_block->video_id_);
if (animations_it != animations.end()) {
LOG_IF(ERROR, !is_looped) << "Receive non-looped animation";
@ -2067,8 +2067,8 @@ unique_ptr<WebPageBlock> get_web_page_block(Td *td, tl_object_ptr<telegram_api::
}
case telegram_api::pageBlockEmbed::ID: {
auto page_block = move_tl_object_as<telegram_api::pageBlockEmbed>(page_block_ptr);
bool is_full_width = (page_block->flags_ & telegram_api::pageBlockEmbed::FULL_WIDTH_MASK) != 0;
bool allow_scrolling = (page_block->flags_ & telegram_api::pageBlockEmbed::ALLOW_SCROLLING_MASK) != 0;
bool is_full_width = page_block->full_width_;
bool allow_scrolling = page_block->allow_scrolling_;
bool has_dimensions = (page_block->flags_ & telegram_api::pageBlockEmbed::W_MASK) != 0;
auto it = (page_block->flags_ & telegram_api::pageBlockEmbed::POSTER_PHOTO_ID_MASK) != 0
? photos.find(page_block->poster_photo_id_)
@ -2158,23 +2158,22 @@ unique_ptr<WebPageBlock> get_web_page_block(Td *td, tl_object_ptr<telegram_api::
}
case telegram_api::pageBlockTable::ID: {
auto page_block = move_tl_object_as<telegram_api::pageBlockTable>(page_block_ptr);
auto is_bordered = (page_block->flags_ & telegram_api::pageBlockTable::BORDERED_MASK) != 0;
auto is_striped = (page_block->flags_ & telegram_api::pageBlockTable::STRIPED_MASK) != 0;
auto is_bordered = page_block->bordered_;
auto is_striped = page_block->striped_;
auto cells = transform(std::move(page_block->rows_), [&](tl_object_ptr<telegram_api::pageTableRow> &&row) {
return transform(std::move(row->cells_), [&](tl_object_ptr<telegram_api::pageTableCell> &&table_cell) {
WebPageBlockTableCell cell;
auto flags = table_cell->flags_;
cell.is_header = (flags & telegram_api::pageTableCell::HEADER_MASK) != 0;
cell.align_center = (flags & telegram_api::pageTableCell::ALIGN_CENTER_MASK) != 0;
cell.is_header = table_cell->header_;
cell.align_center = table_cell->align_center_;
if (!cell.align_center) {
cell.align_right = (flags & telegram_api::pageTableCell::ALIGN_RIGHT_MASK) != 0;
cell.align_right = table_cell->align_right_;
if (!cell.align_right) {
cell.align_left = true;
}
}
cell.valign_middle = (flags & telegram_api::pageTableCell::VALIGN_MIDDLE_MASK) != 0;
cell.valign_middle = table_cell->valign_middle_;
if (!cell.valign_middle) {
cell.valign_bottom = (flags & telegram_api::pageTableCell::VALIGN_BOTTOM_MASK) != 0;
cell.valign_bottom = table_cell->valign_bottom_;
if (!cell.valign_bottom) {
cell.valign_top = true;
}
@ -2182,10 +2181,10 @@ unique_ptr<WebPageBlock> get_web_page_block(Td *td, tl_object_ptr<telegram_api::
if (table_cell->text_ != nullptr) {
cell.text = get_rich_text(std::move(table_cell->text_), documents);
}
if ((flags & telegram_api::pageTableCell::COLSPAN_MASK) != 0) {
if ((table_cell->flags_ & telegram_api::pageTableCell::COLSPAN_MASK) != 0) {
cell.colspan = table_cell->colspan_;
}
if ((flags & telegram_api::pageTableCell::ROWSPAN_MASK) != 0) {
if ((table_cell->flags_ & telegram_api::pageTableCell::ROWSPAN_MASK) != 0) {
cell.rowspan = table_cell->rowspan_;
}
return cell;
@ -2196,7 +2195,7 @@ unique_ptr<WebPageBlock> get_web_page_block(Td *td, tl_object_ptr<telegram_api::
}
case telegram_api::pageBlockDetails::ID: {
auto page_block = move_tl_object_as<telegram_api::pageBlockDetails>(page_block_ptr);
auto is_open = (page_block->flags_ & telegram_api::pageBlockDetails::OPEN_MASK) != 0;
auto is_open = page_block->open_;
return td::make_unique<WebPageBlockDetails>(get_rich_text(std::move(page_block->title_), documents),
get_web_page_blocks(td, std::move(page_block->blocks_), animations,
audios, documents, photos, videos, voice_notes),

View File

@ -6,8 +6,6 @@
//
#include "td/telegram/WebPagesManager.h"
#include "td/telegram/secret_api.h"
#include "td/telegram/AnimationsManager.h"
#include "td/telegram/AudiosManager.h"
#include "td/telegram/AuthManager.h"
@ -23,6 +21,7 @@
#include "td/telegram/MessageEntity.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/Photo.h"
#include "td/telegram/secret_api.h"
#include "td/telegram/StickersManager.h"
#include "td/telegram/Td.h"
#include "td/telegram/TdDb.h"
@ -1457,12 +1456,12 @@ void WebPagesManager::on_get_web_page_instant_view(WebPage *web_page, tl_object_
web_page->instant_view.page_blocks =
get_web_page_blocks(td_, std::move(page->blocks_), animations, audios, documents, photos, videos, voice_notes);
web_page->instant_view.view_count = (page->flags_ & telegram_api::page::VIEWS_MASK) != 0 ? page->views_ : 0;
web_page->instant_view.is_v2 = (page->flags_ & telegram_api::page::V2_MASK) != 0;
web_page->instant_view.is_rtl = (page->flags_ & telegram_api::page::RTL_MASK) != 0;
web_page->instant_view.is_v2 = page->v2_;
web_page->instant_view.is_rtl = page->rtl_;
web_page->instant_view.hash = hash;
web_page->instant_view.url = std::move(page->url_);
web_page->instant_view.is_empty = false;
web_page->instant_view.is_full = (page->flags_ & telegram_api::page::PART_MASK) == 0;
web_page->instant_view.is_full = !page->part_;
web_page->instant_view.is_loaded = true;
LOG(DEBUG) << "Receive web page instant view: "

View File

@ -6,14 +6,13 @@
//
#pragma once
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/DialogId.h"
#include "td/telegram/files/FileId.h"
#include "td/telegram/files/FileSourceId.h"
#include "td/telegram/FullMessageId.h"
#include "td/telegram/SecretInputMedia.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/WebPageId.h"
#include "td/actor/actor.h"

View File

@ -2098,6 +2098,13 @@ class CliClient final : public Actor {
string limit;
get_args(args, chat_id, limit);
send_request(td_api::make_object<td_api::searchChatRecentLocationMessages>(as_chat_id(chat_id), as_limit(limit)));
} else if (op == "gcmca") {
string chat_id;
string filter;
string from_message_id;
get_args(args, chat_id, filter, from_message_id);
send_request(td_api::make_object<td_api::getChatMessageCalendar>(
as_chat_id(chat_id), as_search_messages_filter(filter), as_message_id(from_message_id)));
} else if (op == "SearchAudio" || op == "SearchDocument" || op == "SearchPhoto" || op == "SearchChatPhoto") {
string chat_id;
string offset_message_id;
@ -2106,6 +2113,19 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::searchChatMessages>(as_chat_id(chat_id), query.query, nullptr,
as_message_id(offset_message_id), 0, query.limit,
as_search_messages_filter(op), 0));
} else if (op == "gcmbd") {
string chat_id;
int32 date;
get_args(args, chat_id, date);
send_request(td_api::make_object<td_api::getChatMessageByDate>(as_chat_id(chat_id), date));
} else if (op == "gcsmp") {
string chat_id;
string filter;
string from_message_id;
string limit;
get_args(args, chat_id, filter, from_message_id, limit);
send_request(td_api::make_object<td_api::getChatSparseMessagePositions>(
as_chat_id(chat_id), as_search_messages_filter(filter), as_message_id(from_message_id), as_limit(limit)));
} else if (op == "gcmc") {
string chat_id;
string filter;
@ -2517,6 +2537,8 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::searchEmojis>(args, true, vector<string>()));
} else if (op == "seru") {
send_request(td_api::make_object<td_api::searchEmojis>(args, false, vector<string>{"ru_RU"}));
} else if (op == "gae") {
send_request(td_api::make_object<td_api::getAnimatedEmoji>(args));
} else if (op == "gesu") {
send_request(td_api::make_object<td_api::getEmojiSuggestionsUrl>(args));
} else {
@ -2643,11 +2665,6 @@ class CliClient final : public Actor {
for_album));
} else if (op == "gmli") {
send_request(td_api::make_object<td_api::getMessageLinkInfo>(args));
} else if (op == "gcmbd") {
string chat_id;
int32 date;
get_args(args, chat_id, date);
send_request(td_api::make_object<td_api::getChatMessageByDate>(as_chat_id(chat_id), date));
} else if (op == "gf" || op == "GetFile") {
send_request(td_api::make_object<td_api::getFile>(as_file_id(args)));
} else if (op == "gfdps") {
@ -2783,19 +2800,19 @@ class CliClient final : public Actor {
} else if (op == "scdi" || op == "SendCallDebugInformation") {
send_request(td_api::make_object<td_api::sendCallDebugInformation>(as_call_id(args), "{}"));
} else if (op == "gvcap") {
send_request(td_api::make_object<td_api::getVoiceChatAvailableParticipants>(as_chat_id(args)));
send_request(td_api::make_object<td_api::getVideoChatAvailableParticipants>(as_chat_id(args)));
} else if (op == "svcdp") {
string chat_id;
string participant_id;
get_args(args, chat_id, participant_id);
send_request(td_api::make_object<td_api::setVoiceChatDefaultParticipant>(as_chat_id(chat_id),
send_request(td_api::make_object<td_api::setVideoChatDefaultParticipant>(as_chat_id(chat_id),
as_message_sender(participant_id)));
} else if (op == "cvc") {
string chat_id;
string title;
int32 start_date;
get_args(args, chat_id, title, start_date);
send_request(td_api::make_object<td_api::createVoiceChat>(as_chat_id(chat_id), title, start_date));
send_request(td_api::make_object<td_api::createVideoChat>(as_chat_id(chat_id), title, start_date));
} else if (op == "ggc") {
send_request(td_api::make_object<td_api::getGroupCall>(as_group_call_id(args)));
} else if (op == "ggcss") {
@ -2940,18 +2957,23 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::replacePrimaryChatInviteLink>(as_chat_id(chat_id)));
} else if (op == "ccilt") {
string chat_id;
string name;
int32 expire_date;
int32 member_limit;
get_args(args, chat_id, expire_date, member_limit);
send_request(td_api::make_object<td_api::createChatInviteLink>(as_chat_id(chat_id), expire_date, member_limit));
bool creates_join_request;
get_args(args, chat_id, name, expire_date, member_limit, creates_join_request);
send_request(td_api::make_object<td_api::createChatInviteLink>(as_chat_id(chat_id), name, expire_date,
member_limit, creates_join_request));
} else if (op == "ecil") {
string chat_id;
string invite_link;
string name;
int32 expire_date;
int32 member_limit;
get_args(args, chat_id, invite_link, expire_date, member_limit);
send_request(
td_api::make_object<td_api::editChatInviteLink>(as_chat_id(chat_id), invite_link, expire_date, member_limit));
bool creates_join_request;
get_args(args, chat_id, invite_link, name, expire_date, member_limit, creates_join_request);
send_request(td_api::make_object<td_api::editChatInviteLink>(as_chat_id(chat_id), invite_link, name, expire_date,
member_limit, creates_join_request));
} else if (op == "rcil") {
string chat_id;
string invite_link;
@ -2984,7 +3006,30 @@ class CliClient final : public Actor {
get_args(args, chat_id, invite_link, offset_user_id, offset_date, limit);
send_request(td_api::make_object<td_api::getChatInviteLinkMembers>(
as_chat_id(chat_id), invite_link,
td_api::make_object<td_api::chatInviteLinkMember>(as_user_id(offset_user_id), offset_date), as_limit(limit)));
td_api::make_object<td_api::chatInviteLinkMember>(as_user_id(offset_user_id), offset_date, 0),
as_limit(limit)));
} else if (op == "gcjr") {
string chat_id;
string invite_link;
string query;
string offset_user_id;
int32 offset_date;
string limit;
get_args(args, chat_id, invite_link, query, offset_user_id, offset_date, limit);
send_request(td_api::make_object<td_api::getChatJoinRequests>(
as_chat_id(chat_id), invite_link, query,
td_api::make_object<td_api::chatJoinRequest>(as_user_id(offset_user_id), offset_date, string()),
as_limit(limit)));
} else if (op == "acjr") {
string chat_id;
string user_id;
get_args(args, chat_id, user_id);
send_request(td_api::make_object<td_api::approveChatJoinRequest>(as_chat_id(chat_id), as_user_id(user_id)));
} else if (op == "dcjr") {
string chat_id;
string user_id;
get_args(args, chat_id, user_id);
send_request(td_api::make_object<td_api::declineChatJoinRequest>(as_chat_id(chat_id), as_user_id(user_id)));
} else if (op == "drcil") {
string chat_id;
string invite_link;
@ -3329,7 +3374,8 @@ class CliClient final : public Actor {
string bot_id;
string query;
get_args(args, bot_id, query);
send_request(td_api::make_object<td_api::getInlineQueryResults>(as_user_id(bot_id), 0, nullptr, query, ""));
send_request(td_api::make_object<td_api::getInlineQueryResults>(as_user_id(bot_id), as_chat_id(bot_id), nullptr,
query, ""));
} else if (op == "giqro") {
string bot_id;
string offset;
@ -3680,6 +3726,14 @@ class CliClient final : public Actor {
get_args(args, chat_id, remove_from_the_chat_list, revoke);
send_request(
td_api::make_object<td_api::deleteChatHistory>(as_chat_id(chat_id), remove_from_the_chat_list, revoke));
} else if (op == "dcmbd") {
string chat_id;
int32 min_date;
int32 max_date;
bool revoke;
get_args(args, chat_id, min_date, max_date, revoke);
send_request(
td_api::make_object<td_api::deleteChatMessagesByDate>(as_chat_id(chat_id), min_date, max_date, revoke));
} else if (op == "dmfu") {
string chat_id;
string user_id;

View File

@ -6,8 +6,6 @@
//
#include "td/telegram/files/FileDownloader.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/FileReferenceManager.h"
#include "td/telegram/files/FileLoaderUtils.h"
#include "td/telegram/files/FileType.h"

View File

@ -6,13 +6,12 @@
//
#pragma once
#include "td/telegram/telegram_api.h"
#include "td/telegram/files/FileEncryptionKey.h"
#include "td/telegram/files/FileLoader.h"
#include "td/telegram/files/FileLocation.h"
#include "td/telegram/net/DcId.h"
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/common.h"
#include "td/utils/port/FileFd.h"

View File

@ -6,9 +6,6 @@
//
#include "td/telegram/files/FileGenerateManager.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/files/FileId.h"
#include "td/telegram/files/FileLoaderUtils.h"
#include "td/telegram/files/FileManager.h"
@ -17,6 +14,8 @@
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/Td.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/common.h"
#include "td/utils/format.h"

View File

@ -6,12 +6,11 @@
//
#include "td/telegram/files/FileHashUploader.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/files/FileType.h"
#include "td/telegram/Global.h"
#include "td/telegram/net/DcId.h"
#include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/buffer.h"
#include "td/utils/common.h"

Some files were not shown because too many files have changed in this diff Show More