Merge remote-tracking branch 'td/master'

This commit is contained in:
Andrea Cavalli 2021-12-25 00:25:15 +01:00
commit 7a3cf7ad57
49 changed files with 1047 additions and 725 deletions

View File

@ -1,10 +1,10 @@
if (APPLE)
find_path(READLINE_INCLUDE_DIR readline/readline.h /usr/local/opt/readline/include /opt/local/include /opt/include /usr/local/include /usr/include NO_DEFAULT_PATH)
find_path(READLINE_INCLUDE_DIR readline/readline.h /opt/homebrew/opt/readline/include /usr/local/opt/readline/include /opt/local/include /opt/include /usr/local/include /usr/include NO_DEFAULT_PATH)
endif()
find_path(READLINE_INCLUDE_DIR readline/readline.h)
if (APPLE)
find_library(READLINE_LIBRARY readline /usr/local/opt/readline/lib /opt/local/lib /opt/lib /usr/local/lib /usr/lib NO_DEFAULT_PATH)
find_library(READLINE_LIBRARY readline /opt/homebrew/opt/readline/lib /usr/local/opt/readline/lib /opt/local/lib /opt/lib /usr/local/lib /usr/lib NO_DEFAULT_PATH)
endif()
find_library(READLINE_LIBRARY readline)

View File

@ -6,7 +6,7 @@ if (POLICY CMP0065)
cmake_policy(SET CMP0065 NEW)
endif()
project(TDLib VERSION 1.7.10 LANGUAGES CXX C)
project(TDLib VERSION 1.7.11 LANGUAGES CXX C)
if (NOT DEFINED CMAKE_MODULE_PATH)
set(CMAKE_MODULE_PATH "")
@ -365,7 +365,7 @@ set(TDLIB_SOURCE
td/telegram/MessageSearchFilter.cpp
td/telegram/MessageSender.cpp
td/telegram/MessagesManager.cpp
td/telegram/MessageTtlSetting.cpp
td/telegram/MessageTtl.cpp
td/telegram/misc.cpp
td/telegram/net/AuthDataShared.cpp
td/telegram/net/ConnectionCreator.cpp
@ -571,7 +571,8 @@ set(TDLIB_SOURCE
td/telegram/MessageSearchFilter.h
td/telegram/MessageSender.h
td/telegram/MessagesManager.h
td/telegram/MessageTtlSetting.h
td/telegram/MessageTtl.h
td/telegram/MinChannel.h
td/telegram/misc.h
td/telegram/net/AuthDataShared.h
td/telegram/net/ConnectionCreator.h
@ -680,6 +681,8 @@ set(TDLIB_SOURCE
td/telegram/Game.hpp
td/telegram/InputMessageText.hpp
td/telegram/MessageEntity.hpp
td/telegram/MessageReplyInfo.hpp
td/telegram/MinChannel.hpp
td/telegram/NotificationSettings.hpp
td/telegram/Payments.hpp
td/telegram/Photo.hpp

View File

@ -130,7 +130,7 @@ target_link_libraries(YourTarget PRIVATE Td::TdStatic)
Or you could install `TDLib` and then reference it in your CMakeLists.txt like this:
```
find_package(Td 1.7.10 REQUIRED)
find_package(Td 1.7.11 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

@ -158,7 +158,7 @@ function split_file($file, $chunks, $undo) {
}
if (count($functions) < $chunks) {
fwrite(STDERR, "ERROR: file is too small to be splitted more".PHP_EOL);
fwrite(STDERR, "ERROR: file is too small to be split more".PHP_EOL);
return;
}

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.10 REQUIRED)
find_package(Td 1.7.11 REQUIRED)
add_executable(tdjson_example tdjson_example.cpp)
target_link_libraries(tdjson_example PRIVATE Td::TdJson)

View File

@ -1,6 +1,6 @@
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011">
<Metadata>
<Identity Id="Telegram.Td.UWP" Version="1.7.10" Language="en-US" Publisher="Telegram LLC" />
<Identity Id="Telegram.Td.UWP" Version="1.7.11" 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

@ -52,10 +52,10 @@ authenticationCodeTypeSms length:int32 = AuthenticationCodeType;
//@description An authentication code is delivered via a phone call to the specified phone number @length Length of the code
authenticationCodeTypeCall length:int32 = AuthenticationCodeType;
//@description An authentication code is delivered by an immediately canceled call to the specified phone number. The phone number, from which the call was made, is the code that must be entered automatically @pattern Pattern of the phone number from which the call will be made
//@description An authentication code is delivered by an immediately canceled call to the specified phone number. The phone number that calls is the code that must be entered automatically @pattern Pattern of the phone number from which the call will be made
authenticationCodeTypeFlashCall pattern:string = AuthenticationCodeType;
//@description An authentication code is delivered by an immediately canceled call to the specified phone number. The phone number, from which the call was made, is the code that is supposed to be entered manually by the user @phone_number_prefix Prefix of the phone number from which the call will be made @length Number of digits in the code, excluding the prefix
//@description An authentication code is delivered by an immediately canceled call to the specified phone number. The last digits of the phone number that calls are the code that must be entered manually by the user @phone_number_prefix Prefix of the phone number from which the call will be made @length Number of digits in the code, excluding the prefix
authenticationCodeTypeMissedCall phone_number_prefix:string length:int32 = AuthenticationCodeType;
@ -582,14 +582,14 @@ supergroupMembersFilterBots = SupergroupMembersFilter;
//@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
//@expiration_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. Always 0 if the link requires approval
//@member_count Number of chat members, which joined the chat using the link
//@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, expiration 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 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;
chatInviteLink invite_link:string name:string creator_user_id:int53 date:int32 edit_date:int32 expiration_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;
@ -603,10 +603,10 @@ 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 link counts
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 @approver_user_id User identifier of the chat administrator, approved user join request
//@description Describes a chat member joined a chat via 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
//@description Contains a list of chat members joined a chat via an invite link @total_count Approximate total count of chat members found @members List of chat members, joined a chat via an invite link
chatInviteLinkMembers total_count:int32 members:vector<chatInviteLinkMember> = ChatInviteLinkMembers;
//@description Contains information about a chat invite link
@ -625,10 +625,10 @@ chatInviteLinkInfo chat_id:int53 accessible_for:int32 type:ChatType title:string
//@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
//@description Contains a list of requests to join a chat @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 at most 3 users sent the newest pending join requests
//@description Contains information about pending join requests for a chat @total_count Total number of pending join requests @user_ids Identifiers of at most 3 users sent the newest pending join requests
chatJoinRequestsInfo total_count:int32 user_ids:vector<int53> = ChatJoinRequestsInfo;
@ -661,7 +661,7 @@ basicGroupFullInfo photo:chatPhoto description:string creator_user_id:int53 memb
//@sign_messages True, if messages sent to the channel need to contain information about the sender. This field is only applicable to channels
//@is_slow_mode_enabled True, if the slow mode is enabled in the supergroup
//@is_channel True, if the supergroup is a channel
//@is_broadcast_group True, if the supergroup is a broadcast group, i.e. only administrators can send messages and there is no limit on number of members
//@is_broadcast_group True, if the supergroup is a broadcast group, i.e. only administrators can send messages and there is no limit on the number of members
//@is_verified True, if the supergroup or channel is verified
//@restriction_reason If non-empty, contains a human-readable description of the reason why access to this supergroup or channel must be restricted
//@is_scam True, if many users reported this supergroup or channel as a scam
@ -762,7 +762,7 @@ messageForwardInfo origin:MessageForwardOrigin date:int32 public_service_announc
//@description Contains information about replies to a message
//@reply_count Number of times the message was directly or indirectly replied
//@recent_replier_ids Identifiers of at most 3 recent repliers to the message; available in channels with a discussion supergroup
//@recent_replier_ids Identifiers of at most 3 recent repliers to the message; available in channels with a discussion supergroup. The users and chats are expected to be inaccessible: only their photo and name will be available
//@last_read_inbox_message_id Identifier of the last read incoming reply to the message
//@last_read_outbox_message_id Identifier of the last read outgoing reply to the message
//@last_message_id Identifier of the last reply to the message
@ -836,10 +836,10 @@ 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
//@description Contains information about found messages sent on a specific day @total_count Total number of found messages sent on the day @message First message sent on 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
//@description Contains information about found messages, split 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;
@ -850,9 +850,6 @@ messageCalendar total_count:int32 days:vector<messageCalendarDay> = MessageCalen
//@content Content of the message. Currently, can be only of the type messageText
sponsoredMessage id:int32 sponsor_chat_id:int53 link:InternalLinkType content:MessageContent = SponsoredMessage;
//@description Contains a list of sponsored messages @messages List of sponsored messages
sponsoredMessages messages:vector<sponsoredMessage> = SponsoredMessages;
//@class NotificationSettingsScope @description Describes the types of chats to which notification settings are relevant
@ -907,7 +904,7 @@ chatTypeSecret secret_chat_id:int32 user_id:int53 = ChatType;
//@description Represents a filter of user chats
//@title The title of the filter; 1-12 characters without line feeds
//@icon_name The icon name for short filter representation. If non-empty, must be one of "All", "Unread", "Unmuted", "Bots", "Channels", "Groups", "Private", "Custom", "Setup", "Cat", "Crown", "Favorite", "Flower", "Game", "Home", "Love", "Mask", "Party", "Sport", "Study", "Trade", "Travel", "Work".
//@icon_name The chosen icon name for short filter representation. If non-empty, must be one of "All", "Unread", "Unmuted", "Bots", "Channels", "Groups", "Private", "Custom", "Setup", "Cat", "Crown", "Favorite", "Flower", "Game", "Home", "Love", "Mask", "Party", "Sport", "Study", "Trade", "Travel", "Work".
//-If empty, use getChatFilterDefaultIconName to get default icon name for the filter
//@pinned_chat_ids The chat identifiers of pinned chats in the filtered chat list
//@included_chat_ids The chat identifiers of always included chats in the filtered chat list
@ -925,7 +922,7 @@ chatFilter title:string icon_name:string pinned_chat_ids:vector<int53> included_
//@description Contains basic information about a chat filter
//@id Unique chat filter identifier
//@title The title of the filter; 1-12 characters without line feeds
//@icon_name The icon name for short filter representation. One of "All", "Unread", "Unmuted", "Bots", "Channels", "Groups", "Private", "Custom", "Setup", "Cat", "Crown", "Favorite", "Flower", "Game", "Home", "Love", "Mask", "Party", "Sport", "Study", "Trade", "Travel", "Work"
//@icon_name The chosen or default icon name for short filter representation. One of "All", "Unread", "Unmuted", "Bots", "Channels", "Groups", "Private", "Custom", "Setup", "Cat", "Crown", "Favorite", "Flower", "Game", "Home", "Love", "Mask", "Party", "Sport", "Study", "Trade", "Travel", "Work"
chatFilterInfo id:int32 title:string icon_name:string = ChatFilterInfo;
//@description Describes a recommended chat filter @filter The chat filter @param_description Chat filter description
@ -982,7 +979,7 @@ videoChat group_call_id:int32 has_participants:Bool default_participant_id:Messa
//@permissions Actions that non-administrator chat members are allowed to take in the chat
//@last_message Last message in the chat; may be null
//@positions Positions of the chat in chat lists
//@default_message_sender_id Default identifier of a user or chat that is chosen to send messages in the chat; may be null if the user can't change message sender
//@message_sender_id Identifier of a user or chat that is selected to send messages in the chat; may be null if the user can't change message sender
//@has_protected_content True, if chat content can't be saved locally, forwarded, or copied
//@is_marked_as_unread True, if the chat is marked as unread
//@is_blocked True, if the chat is blocked by the current user and private messages from the chat can't be received
@ -996,7 +993,7 @@ videoChat group_call_id:int32 has_participants:Bool default_participant_id:Messa
//@last_read_outbox_message_id Identifier of the last read outgoing message
//@unread_mention_count Number of unread messages with a mention/reply in the chat
//@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
//@message_ttl 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 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
@ -1004,7 +1001,7 @@ videoChat group_call_id:int32 has_participants:Bool default_participant_id:Messa
//@reply_markup_message_id Identifier of the message from which reply markup needs to be used; 0 if there is no default custom reply markup in the chat
//@draft_message A draft of a message in the chat; may be null
//@client_data Application-specific data associated with the chat. (For example, the chat scroll position or local chat notification settings can be stored here.) Persistent if the message database is used
chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector<chatPosition> default_message_sender_id:MessageSender has_protected_content:Bool is_marked_as_unread:Bool is_blocked:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings message_ttl_setting:int32 theme_name:string action_bar:ChatActionBar video_chat:videoChat pending_join_requests:chatJoinRequestsInfo reply_markup_message_id:int53 draft_message:draftMessage client_data:string = Chat;
chat id:int53 type:ChatType title:string photo:chatPhotoInfo permissions:chatPermissions last_message:message positions:vector<chatPosition> message_sender_id:MessageSender has_protected_content:Bool is_marked_as_unread:Bool is_blocked:Bool has_scheduled_messages:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_be_reported:Bool default_disable_notification:Bool unread_count:int32 last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 unread_mention_count:int32 notification_settings:chatNotificationSettings message_ttl: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;
@ -1832,7 +1829,7 @@ messageChatDeletePhoto = MessageContent;
//@description New chat members were added @member_user_ids User identifiers of the new members
messageChatAddMembers member_user_ids:vector<int53> = MessageContent;
//@description A new member joined the chat by invite link
//@description A new member joined the chat via an invite link
messageChatJoinByLink = MessageContent;
//@description A new member was accepted to the chat by an administrator
@ -1856,7 +1853,7 @@ messageScreenshotTaken = MessageContent;
//@description A theme in the chat has been changed @theme_name If non-empty, name of a new theme, set for the chat. Otherwise chat theme was reset to the default one
messageChatSetTheme theme_name:string = MessageContent;
//@description The TTL (Time To Live) setting for messages in the chat has been changed @ttl New message TTL setting
//@description The TTL (Time To Live) setting for messages in the chat has been changed @ttl New message TTL
messageChatSetTtl ttl:int32 = MessageContent;
//@description A non-standard action has happened in the chat @text Message text to be shown in the chat
@ -2566,7 +2563,7 @@ chatEventMessageUnpinned message:message = ChatEventAction;
//@description A new member joined the chat
chatEventMemberJoined = ChatEventAction;
//@description A new member joined the chat by an invite link @invite_link Invite link used to join the chat
//@description A new member joined the chat via 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
@ -2608,8 +2605,8 @@ chatEventLinkedChatChanged old_linked_chat_id:int53 new_linked_chat_id:int53 = C
//@description The slow_mode_delay setting of a supergroup was changed @old_slow_mode_delay Previous value of slow_mode_delay, in seconds @new_slow_mode_delay New value of slow_mode_delay, in seconds
chatEventSlowModeDelayChanged old_slow_mode_delay:int32 new_slow_mode_delay:int32 = ChatEventAction;
//@description The message TTL setting was changed @old_message_ttl_setting Previous value of message_ttl_setting @new_message_ttl_setting New value of message_ttl_setting
chatEventMessageTtlSettingChanged old_message_ttl_setting:int32 new_message_ttl_setting:int32 = ChatEventAction;
//@description The message TTL was changed @old_message_ttl Previous value of message_ttl @new_message_ttl New value of message_ttl
chatEventMessageTtlChanged old_message_ttl:int32 new_message_ttl:int32 = ChatEventAction;
//@description The sign_messages setting of a channel was toggled @sign_messages New value of sign_messages
chatEventSignMessagesToggled sign_messages:Bool = ChatEventAction;
@ -2638,8 +2635,8 @@ chatEventInviteLinkDeleted invite_link:chatInviteLink = 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 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 video chat was ended @group_call_id Identifier of the video chat. The video chat can be received through the method getGroupCall
chatEventVideoChatEnded group_call_id:int32 = 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;
@ -2650,8 +2647,8 @@ chatEventVideoChatParticipantVolumeLevelChanged participant_id:MessageSender vol
//@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;
//@description Represents a chat event @id Chat event identifier @date Point in time (Unix timestamp) when the event happened @member_id Identifier of the user or chat who performed the action @action The action
chatEvent id:int64 date:int32 member_id:MessageSender action:ChatEventAction = ChatEvent;
//@description Contains a list of chat events @events List of events
chatEvents events:vector<chatEvent> = ChatEvents;
@ -2708,38 +2705,38 @@ localizationTargetInfo language_packs:vector<languagePackInfo> = LocalizationTar
//@class DeviceToken @description Represents a data needed to subscribe for push notifications through registerDevice method. To use specific push notification service, the correct application platform must be specified and a valid server authentication data must be uploaded at https://my.telegram.org
//@description A token for Firebase Cloud Messaging @token Device registration token; may be empty to de-register a device @encrypt True, if push notifications must be additionally encrypted
//@description A token for Firebase Cloud Messaging @token Device registration token; may be empty to deregister a device @encrypt True, if push notifications must be additionally encrypted
deviceTokenFirebaseCloudMessaging token:string encrypt:Bool = DeviceToken;
//@description A token for Apple Push Notification service @device_token Device token; may be empty to de-register a device @is_app_sandbox True, if App Sandbox is enabled
//@description A token for Apple Push Notification service @device_token Device token; may be empty to deregister a device @is_app_sandbox True, if App Sandbox is enabled
deviceTokenApplePush device_token:string is_app_sandbox:Bool = DeviceToken;
//@description A token for Apple Push Notification service VoIP notifications @device_token Device token; may be empty to de-register a device @is_app_sandbox True, if App Sandbox is enabled @encrypt True, if push notifications must be additionally encrypted
//@description A token for Apple Push Notification service VoIP notifications @device_token Device token; may be empty to deregister a device @is_app_sandbox True, if App Sandbox is enabled @encrypt True, if push notifications must be additionally encrypted
deviceTokenApplePushVoIP device_token:string is_app_sandbox:Bool encrypt:Bool = DeviceToken;
//@description A token for Windows Push Notification Services @access_token The access token that will be used to send notifications; may be empty to de-register a device
//@description A token for Windows Push Notification Services @access_token The access token that will be used to send notifications; may be empty to deregister a device
deviceTokenWindowsPush access_token:string = DeviceToken;
//@description A token for Microsoft Push Notification Service @channel_uri Push notification channel URI; may be empty to de-register a device
//@description A token for Microsoft Push Notification Service @channel_uri Push notification channel URI; may be empty to deregister a device
deviceTokenMicrosoftPush channel_uri:string = DeviceToken;
//@description A token for Microsoft Push Notification Service VoIP channel @channel_uri Push notification channel URI; may be empty to de-register a device
//@description A token for Microsoft Push Notification Service VoIP channel @channel_uri Push notification channel URI; may be empty to deregister a device
deviceTokenMicrosoftPushVoIP channel_uri:string = DeviceToken;
//@description A token for web Push API @endpoint Absolute URL exposed by the push service where the application server can send push messages; may be empty to de-register a device
//@description A token for web Push API @endpoint Absolute URL exposed by the push service where the application server can send push messages; may be empty to deregister a device
//@p256dh_base64url Base64url-encoded P-256 elliptic curve Diffie-Hellman public key @auth_base64url Base64url-encoded authentication secret
deviceTokenWebPush endpoint:string p256dh_base64url:string auth_base64url:string = DeviceToken;
//@description A token for Simple Push API for Firefox OS @endpoint Absolute URL exposed by the push service where the application server can send push messages; may be empty to de-register a device
//@description A token for Simple Push API for Firefox OS @endpoint Absolute URL exposed by the push service where the application server can send push messages; may be empty to deregister a device
deviceTokenSimplePush endpoint:string = DeviceToken;
//@description A token for Ubuntu Push Client service @token Token; may be empty to de-register a device
//@description A token for Ubuntu Push Client service @token Token; may be empty to deregister a device
deviceTokenUbuntuPush token:string = DeviceToken;
//@description A token for BlackBerry Push Service @token Token; may be empty to de-register a device
//@description A token for BlackBerry Push Service @token Token; may be empty to deregister a device
deviceTokenBlackBerryPush token:string = DeviceToken;
//@description A token for Tizen Push Service @reg_id Push service registration identifier; may be empty to de-register a device
//@description A token for Tizen Push Service @reg_id Push service registration identifier; may be empty to deregister a device
deviceTokenTizenPush reg_id:string = DeviceToken;
@ -2966,7 +2963,7 @@ pushMessageContentChatSetTheme theme_name:string = PushMessageContent;
//@is_left True, if the user has left the group themselves
pushMessageContentChatDeleteMember member_name:string is_current_user:Bool is_left:Bool = PushMessageContent;
//@description A new member joined the chat by invite link
//@description A new member joined the chat via an invite link
pushMessageContentChatJoinByLink = PushMessageContent;
//@description A new member was accepted to the chat by an administrator
@ -3485,14 +3482,14 @@ tMeUrls urls:vector<tMeUrl> = TMeUrls;
//@description Suggests the user to enable "archive_and_mute_new_chats_from_unknown_users" option
suggestedActionEnableArchiveAndMuteNewChats = SuggestedAction;
//@description Suggests the user to check whether 2-step verification password is still remembered
//@description Suggests the user to check whether they still remember their 2-step verification password
suggestedActionCheckPassword = SuggestedAction;
//@description Suggests the user to check whether authorization phone number is correct and change the phone number if it is inaccessible
suggestedActionCheckPhoneNumber = SuggestedAction;
//@description Suggests the user to see a hint about meaning of one and two ticks on sent messages
suggestedActionSeeTicksHint = SuggestedAction;
//@description Suggests the user to view a hint about the meaning of one and two check marks on sent messages
suggestedActionViewChecksHint = SuggestedAction;
//@description Suggests the user to convert specified supergroup to a broadcast group @supergroup_id Supergroup identifier
suggestedActionConvertToBroadcastGroup supergroup_id:int53 = SuggestedAction;
@ -3743,50 +3740,26 @@ updateChatLastMessage chat_id:int53 last_message:message positions:vector<chatPo
//@description The position of a chat in a chat list has changed. Instead of this update updateChatLastMessage or updateChatDraftMessage might be sent @chat_id Chat identifier @position New chat position. If new order is 0, then the chat needs to be removed from the list
updateChatPosition chat_id:int53 position:chatPosition = Update;
//@description The default message sender that is chosen to send messages in a chat has changed @chat_id Chat identifier @default_message_sender_id New value of default_message_sender_id; may be null if the user can't change message sender
updateChatDefaultMessageSenderId chat_id:int53 default_message_sender_id:MessageSender = Update;
//@description A chat content was allowed or restricted for saving @chat_id Chat identifier @has_protected_content New value of has_protected_content
updateChatHasProtectedContent chat_id:int53 has_protected_content:Bool = Update;
//@description A chat was marked as unread or was read @chat_id Chat identifier @is_marked_as_unread New value of is_marked_as_unread
updateChatIsMarkedAsUnread chat_id:int53 is_marked_as_unread:Bool = Update;
//@description A chat was blocked or unblocked @chat_id Chat identifier @is_blocked New value of is_blocked
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 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;
//@description Incoming messages were read or the number of unread messages has been changed @chat_id Chat identifier @last_read_inbox_message_id Identifier of the last read incoming message @unread_count The number of unread messages left in the chat
updateChatReadInbox chat_id:int53 last_read_inbox_message_id:int53 unread_count:int32 = Update;
//@description Outgoing messages were read @chat_id Chat identifier @last_read_outbox_message_id Identifier of last read outgoing message
updateChatReadOutbox chat_id:int53 last_read_outbox_message_id:int53 = Update;
//@description The chat unread_mention_count has changed @chat_id Chat identifier @unread_mention_count The number of unread mention messages left in the chat
updateChatUnreadMentionCount chat_id:int53 unread_mention_count:int32 = Update;
//@description Notification settings for a chat were changed @chat_id Chat identifier @notification_settings The new notification settings
updateChatNotificationSettings chat_id:int53 notification_settings:chatNotificationSettings = Update;
//@description Notification settings for some type of chats were updated @scope Types of chats for which notification settings were updated @notification_settings The new notification settings
updateScopeNotificationSettings scope:NotificationSettingsScope notification_settings:scopeNotificationSettings = Update;
//@description The message Time To Live setting for a chat was changed @chat_id Chat identifier @message_ttl_setting New value of message_ttl_setting
updateChatMessageTtlSetting chat_id:int53 message_ttl_setting:int32 = Update;
//@description The chat action bar was changed @chat_id Chat identifier @action_bar The new value of the action bar; may be null
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 A chat draft has changed. Be aware that the update may come in the currently opened chat but with old content of the draft. If the user has changed the content of the draft, this update mustn't be applied @chat_id Chat identifier @draft_message The new draft message; may be null @positions The new chat positions in the chat lists
updateChatDraftMessage chat_id:int53 draft_message:draftMessage positions:vector<chatPosition> = Update;
//@description The message sender that is selected to send messages in a chat has changed @chat_id Chat identifier @message_sender_id New value of message_sender_id; may be null if the user can't change message sender
updateChatMessageSender chat_id:int53 message_sender_id:MessageSender = Update;
//@description The message Time To Live setting for a chat was changed @chat_id Chat identifier @message_ttl New value of message_ttl
updateChatMessageTtl chat_id:int53 message_ttl:int32 = Update;
//@description Notification settings for a chat were changed @chat_id Chat identifier @notification_settings The new notification settings
updateChatNotificationSettings chat_id:int53 notification_settings:chatNotificationSettings = 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;
@ -3795,8 +3768,29 @@ updateChatPendingJoinRequests chat_id:int53 pending_join_requests:chatJoinReques
//@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;
//@description A chat draft has changed. Be aware that the update may come in the currently opened chat but with old content of the draft. If the user has changed the content of the draft, this update mustn't be applied @chat_id Chat identifier @draft_message The new draft message; may be null @positions The new chat positions in the chat lists
updateChatDraftMessage chat_id:int53 draft_message:draftMessage positions:vector<chatPosition> = 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 unread_mention_count has changed @chat_id Chat identifier @unread_mention_count The number of unread mention messages left in the chat
updateChatUnreadMentionCount chat_id:int53 unread_mention_count:int32 = 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;
//@description A chat content was allowed or restricted for saving @chat_id Chat identifier @has_protected_content New value of has_protected_content
updateChatHasProtectedContent chat_id:int53 has_protected_content:Bool = Update;
//@description A chat'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 was blocked or unblocked @chat_id Chat identifier @is_blocked New value of is_blocked
updateChatIsBlocked chat_id:int53 is_blocked:Bool = Update;
//@description A chat was marked as unread or was read @chat_id Chat identifier @is_marked_as_unread New value of is_marked_as_unread
updateChatIsMarkedAsUnread chat_id:int53 is_marked_as_unread:Bool = Update;
//@description The list of chat filters or a chat filter has changed @chat_filters The new list of chat filters
updateChatFilters chat_filters:vector<chatFilterInfo> = Update;
@ -3804,6 +3798,9 @@ updateChatFilters chat_filters:vector<chatFilterInfo> = Update;
//@description The number of online group members has changed. This update with non-zero count is sent only for currently opened chats. There is no guarantee that it will be sent just after the count has changed @chat_id Identifier of the chat @online_member_count New number of online members in the chat, or 0 if unknown
updateChatOnlineMemberCount chat_id:int53 online_member_count:int32 = Update;
//@description Notification settings for some type of chats were updated @scope Types of chats for which notification settings were updated @notification_settings The new notification settings
updateScopeNotificationSettings scope:NotificationSettingsScope notification_settings:scopeNotificationSettings = Update;
//@description A notification was changed @notification_group_id Unique notification group identifier @notification Changed notification
updateNotification notification_group_id:int32 notification:notification = Update;
@ -4362,7 +4359,7 @@ getChatMessageByDate chat_id:int53 date:int32 = Message;
//@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"
//@description Returns information about the next messages of the specified type in the chat split 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, 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
@ -4381,8 +4378,8 @@ getChatScheduledMessages chat_id:int53 = Messages;
//@limit The maximum number of messages to be returned; must be positive and can't be greater than 100. For optimal performance, the number of returned messages is chosen by TDLib and can be smaller than the specified limit
getMessagePublicForwards chat_id:int53 message_id:int53 offset:string limit:int32 = FoundMessages;
//@description Returns sponsored messages to be shown in a chat; for channel chats only @chat_id Identifier of the chat
getChatSponsoredMessages chat_id:int53 = SponsoredMessages;
//@description Returns sponsored message to be shown in a chat; for channel chats only. Returns a 404 error if there is no sponsored message in the chat @chat_id Identifier of the chat
getChatSponsoredMessage chat_id:int53 = SponsoredMessage;
//@description Informs TDLib that a sponsored message was viewed by the user @chat_id Identifier of the chat with the sponsored message @sponsored_message_id The identifier of the sponsored message being viewed
viewSponsoredMessage chat_id:int53 sponsored_message_id:int32 = Ok;
@ -4416,8 +4413,8 @@ getMessageLinkInfo url:string = MessageLinkInfo;
//@description Returns list of message sender identifiers, which can be used to send messages in a chat @chat_id Chat identifier
getChatAvailableMessageSenders chat_id:int53 = MessageSenders;
//@description Changes default message sender that is chosen in a chat @chat_id Chat identifier @default_message_sender_id New default message sender in the chat
setChatDefaultMessageSender chat_id:int53 default_message_sender_id:MessageSender = Ok;
//@description Selects a message sender to send messages in a chat @chat_id Chat identifier @message_sender_id New message sender for the chat
setChatMessageSender chat_id:int53 message_sender_id:MessageSender = Ok;
//@description Sends a message. Returns the sent message
//@chat_id Target chat
@ -4788,10 +4785,10 @@ setChatTitle chat_id:int53 title:string = Ok;
//@chat_id Chat identifier @photo New chat photo; pass null to delete the chat photo
setChatPhoto chat_id:int53 photo:InputChatPhoto = Ok;
//@description Changes the message TTL setting (sets a new self-destruct timer) in a chat. Requires can_delete_messages administrator right in basic groups, supergroups and channels
//-Message TTL setting of a chat with the current user (Saved Messages) and the chat 777000 (Telegram) can't be changed
//@description Changes the message TTL in a chat. Requires can_delete_messages administrator right in basic groups, supergroups and channels
//-Message TTL can't be changed in a chat with the current user (Saved Messages) and the chat 777000 (Telegram)
//@chat_id Chat identifier @ttl New TTL value, in seconds; must be one of 0, 86400, 7 * 86400, or 31 * 86400 unless the chat is secret
setChatMessageTtlSetting chat_id:int53 ttl:int32 = Ok;
setChatMessageTtl chat_id:int53 ttl:int32 = Ok;
//@description Changes the chat members permissions. Supported only for basic groups and supergroups. Requires can_restrict_members administrator right
//@chat_id Chat identifier @permissions New non-administrator members permissions in the chat
@ -4992,19 +4989,19 @@ 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
//@expiration_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 via the link simultaneously; 0-99999; pass 0 if not limited
//@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;
createChatInviteLink chat_id:int53 name:string expiration_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
//@expiration_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 via the link simultaneously; 0-99999; pass 0 if not limited
//@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;
editChatInviteLink chat_id:int53 invite_link:string name:string expiration_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
@ -5023,7 +5020,7 @@ getChatInviteLinkCounts chat_id:int53 = ChatInviteLinkCounts;
//@limit The maximum number of invite links to return; up to 100
getChatInviteLinks chat_id:int53 creator_user_id:int53 is_revoked:Bool offset_date:int32 offset_invite_link:string limit:int32 = ChatInviteLinks;
//@description Returns chat members joined a chat by an invite link. 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 for which to return chat members
//@description Returns chat members joined a chat via an invite link. 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 for which to return chat members
//@offset_member A chat member from which to return next chat members; pass null to get results from the beginning @limit The maximum number of chat members to return; up to 100
getChatInviteLinkMembers chat_id:int53 invite_link:string offset_member:chatInviteLinkMember limit:int32 = ChatInviteLinkMembers;
@ -5052,7 +5049,7 @@ joinChatByInviteLink invite_link:string = Chat;
//@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
//@limit The maximum number of requests to join the chat to return
getChatJoinRequests chat_id:int53 invite_link:string query:string offset_request:chatJoinRequest limit:int32 = ChatJoinRequests;
//@description Handles a pending join request in a chat @chat_id Chat identifier @user_id Identifier of the user that sent the request @approve True, if the request is approved. Otherwise the request is declived
@ -5084,10 +5081,10 @@ 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 video chats in a chat @chat_id Chat identifier
//@description Returns list of participant identifiers, on whose behalf a video chat in the chat can be joined @chat_id Chat identifier
getVideoChatAvailableParticipants chat_id:int53 = MessageSenders;
//@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
//@description Changes default participant identifier, on whose behalf a video chat in the chat will be joined @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 video chat (a group call bound to a chat). Available only for basic groups, supergroups and channels; requires can_manage_video_chats rights
@ -5185,8 +5182,8 @@ loadGroupCallParticipants group_call_id:int32 limit:int32 = Ok;
//@description Leaves a group call @group_call_id Group call identifier
leaveGroupCall group_call_id:int32 = Ok;
//@description Discards a group call. Requires groupCall.can_be_managed @group_call_id Group call identifier
discardGroupCall group_call_id:int32 = Ok;
//@description Ends a group call. Requires groupCall.can_be_managed @group_call_id Group call identifier
endGroupCall group_call_id:int32 = Ok;
//@description Returns a file with a segment of a group call stream in a modified OGG format for audio or MPEG-4 format for video
//@group_call_id Group call identifier

View File

@ -25,20 +25,11 @@
# include <libkern/OSByteOrder.h>
# define htobe16(x) OSSwapHostToBigInt16(x)
# define htole16(x) OSSwapHostToLittleInt16(x)
# define be16toh(x) OSSwapBigToHostInt16(x)
# define le16toh(x) OSSwapLittleToHostInt16(x)
# define htobe32(x) OSSwapHostToBigInt32(x)
# define htole32(x) OSSwapHostToLittleInt32(x)
# define be32toh(x) OSSwapBigToHostInt32(x)
# define le32toh(x) OSSwapLittleToHostInt32(x)
# define htobe64(x) OSSwapHostToBigInt64(x)
# define htole64(x) OSSwapHostToLittleInt64(x)
# define be64toh(x) OSSwapBigToHostInt64(x)
# define le64toh(x) OSSwapLittleToHostInt64(x)
# define __BYTE_ORDER BYTE_ORDER
# define __BIG_ENDIAN BIG_ENDIAN
@ -53,15 +44,6 @@
# include <sys/endian.h>
# define be16toh(x) betoh16(x)
# define le16toh(x) letoh16(x)
# define be32toh(x) betoh32(x)
# define le32toh(x) letoh32(x)
# define be64toh(x) betoh64(x)
# define le64toh(x) letoh64(x)
#elif defined(__WINDOWS__)
# include <winsock2.h>
@ -71,38 +53,20 @@
# if BYTE_ORDER == LITTLE_ENDIAN
# define htobe16(x) htons(x)
# define htole16(x) (x)
# define be16toh(x) ntohs(x)
# define le16toh(x) (x)
# define htobe32(x) htonl(x)
# define htole32(x) (x)
# define be32toh(x) ntohl(x)
# define le32toh(x) (x)
# define htobe64(x) htonll(x)
# define htole64(x) (x)
# define be64toh(x) ntohll(x)
# define le64toh(x) (x)
# elif BYTE_ORDER == BIG_ENDIAN
/* that would be xbox 360 */
# define htobe16(x) (x)
# define htole16(x) __builtin_bswap16(x)
# define be16toh(x) (x)
# define le16toh(x) __builtin_bswap16(x)
# define htobe32(x) (x)
# define htole32(x) __builtin_bswap32(x)
# define be32toh(x) (x)
# define le32toh(x) __builtin_bswap32(x)
# define htobe64(x) (x)
# define htole64(x) __builtin_bswap64(x)
# define be64toh(x) (x)
# define le64toh(x) __builtin_bswap64(x)
# else

View File

@ -85,14 +85,14 @@ void print_backtrace (void) {
}
#else
void print_backtrace (void) {
if (fwrite ("No libexec. Backtrace disabled\n", 32, 1, stderr) < 0) {
if (fwrite ("No libexec. Backtrace disabled\n", 32, 1, stderr) != 1) {
// Sad thing
}
}
#endif
void sig_segv_handler (int signum __attribute__ ((unused))) {
if (fwrite ("SIGSEGV received\n", 18, 1, stderr) < 0) {
if (fwrite ("SIGSEGV received\n", 18, 1, stderr) != 1) {
// Sad thing
}
print_backtrace ();
@ -100,7 +100,7 @@ void sig_segv_handler (int signum __attribute__ ((unused))) {
}
void sig_abrt_handler (int signum __attribute__ ((unused))) {
if (fwrite ("SIGABRT received\n", 18, 1, stderr) < 0) {
if (fwrite ("SIGABRT received\n", 18, 1, stderr) != 1) {
// Sad thing
}
print_backtrace ();

View File

@ -274,11 +274,16 @@ class TdReceiver {
output_queue_->init();
}
ClientManager::Response receive(double timeout) {
ClientManager::Response receive(double timeout, bool from_manager) {
VLOG(td_requests) << "Begin to wait for updates with timeout " << timeout;
auto is_locked = receive_lock_.exchange(true);
if (is_locked) {
LOG(FATAL) << "Receive is called after Client destroy, or simultaneously from different threads";
if (from_manager) {
LOG(FATAL) << "Receive must not be called simultaneously from two different threads, but this has just "
"happened. Call it from a fixed thread, dedicated for updates and response processing.";
} else {
LOG(FATAL) << "Receive is called after Client destroy, or simultaneously from different threads";
}
}
auto response = receive_unlocked(clamp(timeout, 0.0, 1000000.0));
is_locked = receive_lock_.exchange(false);
@ -424,7 +429,11 @@ class MultiImplPool {
if (impls_.empty()) {
init_openssl_threads();
impls_.resize(clamp(thread::hardware_concurrency(), 8u, 20u) * 5 / 4);
auto max_client_threads = clamp(thread::hardware_concurrency(), 8u, 20u) * 5 / 4;
#if TD_OPENBSD
max_client_threads = td::min(max_client_threads, 7u);
#endif
impls_.resize(max_client_threads);
CHECK(impls_.size() * (1 + MultiImpl::ADDITIONAL_THREAD_COUNT + 1 /* IOCP */) < 128);
net_query_stats_ = std::make_shared<NetQueryStats>();
@ -505,7 +514,7 @@ class ClientManager::Impl final {
}
Response receive(double timeout) {
auto response = receiver_.receive(timeout);
auto response = receiver_.receive(timeout, true);
if (response.request_id == 0 && response.object != nullptr &&
response.object->get_id() == td_api::updateAuthorizationState::ID &&
static_cast<const td_api::updateAuthorizationState *>(response.object.get())->authorization_state_->get_id() ==
@ -594,7 +603,7 @@ class Client::Impl final {
}
Response receive(double timeout) {
auto response = receiver_.receive(timeout);
auto response = receiver_.receive(timeout, false);
Response old_response;
old_response.id = response.request_id;
@ -609,7 +618,7 @@ class Client::Impl final {
~Impl() {
multi_impl_->close(td_id_);
while (!ExitGuard::is_exited()) {
auto response = receiver_.receive(0.1);
auto response = receiver_.receive(0.1, false);
if (response.object == nullptr && response.client_id != 0 && response.request_id == 0) {
break;
}

View File

@ -17,122 +17,7 @@
namespace td {
/**
* Native C++ interface for interaction with TDLib.
*
* The TDLib instance is created for the lifetime of the Client object.
* Requests to TDLib can be sent using the Client::send method from any thread.
* New updates and responses to requests can be received using the Client::receive method from any thread,
* this function must not be called simultaneously from two different threads. Also note that all updates and
* responses to requests should be applied in the same order as they were received, to ensure consistency.
* Given this information, it's advisable to call this function from a dedicated thread.
* Some service TDLib requests can be executed synchronously from any thread using the Client::execute method.
*
* General pattern of usage:
* \code
* std::shared_ptr<td::Client> client = std::make_shared<td::Client>();
* // somehow share the client with other threads, which will be able to send requests via client->send
*
* const double WAIT_TIMEOUT = 10.0; // seconds
* bool is_closed = false; // should be set to true, when updateAuthorizationState with
* // authorizationStateClosed is received
* while (!is_closed) {
* auto response = client->receive(WAIT_TIMEOUT);
* if (response.object == nullptr) {
* continue;
* }
*
* if (response.id == 0) {
* // process response.object as an incoming update of type td_api::Update
* } else {
* // process response.object as an answer to a sent request with id response.id
* }
* }
* \endcode
*/
class Client final {
public:
/**
* Creates a new TDLib client.
*/
Client();
/**
* A request to the TDLib.
*/
struct Request {
/**
* Request identifier.
* Responses to TDLib requests will have the same id as the corresponding request.
* Updates from TDLib will have id == 0, incoming requests are thus disallowed to have id == 0.
*/
std::uint64_t id;
/**
* TDLib API function representing a request to TDLib.
*/
td_api::object_ptr<td_api::Function> function;
};
/**
* Sends request to TDLib. May be called from any thread.
* \param[in] request Request to TDLib.
*/
void send(Request &&request);
/**
* A response to a request, or an incoming update from TDLib.
*/
struct Response {
/**
* TDLib request identifier, which corresponds to the response, or 0 for incoming updates from TDLib.
*/
std::uint64_t id;
/**
* TDLib API object representing a response to a TDLib request or an incoming update.
*/
td_api::object_ptr<td_api::Object> object;
};
/**
* Receives incoming updates and request responses from TDLib. May be called from any thread, but shouldn't be
* called simultaneously from two different threads.
* \param[in] timeout The maximum number of seconds allowed for this function to wait for new data.
* \return An incoming update or request response. The object returned in the response may be a nullptr
* if the timeout expires.
*/
Response receive(double timeout);
/**
* Synchronously executes TDLib requests. Only a few requests can be executed synchronously.
* May be called from any thread.
* \param[in] request Request to the TDLib.
* \return The request response.
*/
static Response execute(Request &&request);
/**
* Destroys the client and TDLib instance.
*/
~Client();
/**
* Move constructor.
*/
Client(Client &&other) noexcept;
/**
* Move assignment operator.
*/
Client &operator=(Client &&other) noexcept;
private:
class Impl;
std::unique_ptr<Impl> impl_;
};
/**
* The future native C++ interface for interaction with TDLib.
* The native C++ interface for interaction with TDLib.
*
* A TDLib client instance can be created through the method ClientManager::create_client_id.
* Requests can be sent using the method ClientManager::send from any thread.
@ -286,4 +171,119 @@ class ClientManager final {
std::unique_ptr<Impl> impl_;
};
/**
* Old native C++ interface for interaction with TDLib to be removed in TDLib 2.0.0.
*
* The TDLib instance is created for the lifetime of the Client object.
* Requests to TDLib can be sent using the Client::send method from any thread.
* New updates and responses to requests can be received using the Client::receive method from any thread,
* this function must not be called simultaneously from two different threads. Also note that all updates and
* responses to requests should be applied in the same order as they were received, to ensure consistency.
* Given this information, it's advisable to call this function from a dedicated thread.
* Some service TDLib requests can be executed synchronously from any thread using the Client::execute method.
*
* General pattern of usage:
* \code
* std::shared_ptr<td::Client> client = std::make_shared<td::Client>();
* // somehow share the client with other threads, which will be able to send requests via client->send
*
* const double WAIT_TIMEOUT = 10.0; // seconds
* bool is_closed = false; // should be set to true, when updateAuthorizationState with
* // authorizationStateClosed is received
* while (!is_closed) {
* auto response = client->receive(WAIT_TIMEOUT);
* if (response.object == nullptr) {
* continue;
* }
*
* if (response.id == 0) {
* // process response.object as an incoming update of type td_api::Update
* } else {
* // process response.object as an answer to a sent request with id response.id
* }
* }
* \endcode
*/
class Client final {
public:
/**
* Creates a new TDLib client.
*/
Client();
/**
* A request to the TDLib.
*/
struct Request {
/**
* Request identifier.
* Responses to TDLib requests will have the same id as the corresponding request.
* Updates from TDLib will have id == 0, incoming requests are thus disallowed to have id == 0.
*/
std::uint64_t id;
/**
* TDLib API function representing a request to TDLib.
*/
td_api::object_ptr<td_api::Function> function;
};
/**
* Sends request to TDLib. May be called from any thread.
* \param[in] request Request to TDLib.
*/
void send(Request &&request);
/**
* A response to a request, or an incoming update from TDLib.
*/
struct Response {
/**
* TDLib request identifier, which corresponds to the response, or 0 for incoming updates from TDLib.
*/
std::uint64_t id;
/**
* TDLib API object representing a response to a TDLib request or an incoming update.
*/
td_api::object_ptr<td_api::Object> object;
};
/**
* Receives incoming updates and request responses from TDLib. May be called from any thread, but shouldn't be
* called simultaneously from two different threads.
* \param[in] timeout The maximum number of seconds allowed for this function to wait for new data.
* \return An incoming update or request response. The object returned in the response may be a nullptr
* if the timeout expires.
*/
Response receive(double timeout);
/**
* Synchronously executes TDLib requests. Only a few requests can be executed synchronously.
* May be called from any thread.
* \param[in] request Request to the TDLib.
* \return The request response.
*/
static Response execute(Request &&request);
/**
* Destroys the client and TDLib instance.
*/
~Client();
/**
* Move constructor.
*/
Client(Client &&other) noexcept;
/**
* Move assignment operator.
*/
Client &operator=(Client &&other) noexcept;
private:
class Impl;
std::unique_ptr<Impl> impl_;
};
} // namespace td

View File

@ -25,7 +25,8 @@
#include "td/telegram/MemoryManager.h"
#include "td/telegram/MessageSender.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/MessageTtlSetting.h"
#include "td/telegram/MessageTtl.h"
#include "td/telegram/MinChannel.h"
#include "td/telegram/misc.h"
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/NotificationManager.h"
@ -1974,7 +1975,7 @@ class ImportChatInviteQuery final : public Td::ResultHandler {
auto dialog_ids = UpdatesManager::get_chat_dialog_ids(ptr.get());
if (dialog_ids.size() != 1u) {
LOG(ERROR) << "Receive wrong result for ImportChatInviteQuery: " << to_string(ptr);
return on_error(Status::Error(500, "Internal Server Error: failed to join chat by invite link"));
return on_error(Status::Error(500, "Internal Server Error: failed to join chat via invite link"));
}
auto dialog_id = dialog_ids[0];
@ -4606,6 +4607,10 @@ const DialogPhoto *ContactsManager::get_chat_dialog_photo(ChatId chat_id) const
const DialogPhoto *ContactsManager::get_channel_dialog_photo(ChannelId channel_id) const {
auto c = get_channel(channel_id);
if (c == nullptr) {
auto min_channel = get_min_channel(channel_id);
if (min_channel != nullptr) {
return &min_channel->photo_;
}
return nullptr;
}
return &c->photo;
@ -4644,6 +4649,10 @@ string ContactsManager::get_chat_title(ChatId chat_id) const {
string ContactsManager::get_channel_title(ChannelId channel_id) const {
auto c = get_channel(channel_id);
if (c == nullptr) {
auto min_channel = get_min_channel(channel_id);
if (min_channel != nullptr) {
return min_channel->title_;
}
return string();
}
return c->title;
@ -10149,8 +10158,8 @@ void ContactsManager::update_secret_chat(SecretChat *c, SecretChatId secret_chat
c->is_state_changed = false;
}
if (c->is_ttl_changed) {
send_closure_later(G()->messages_manager(), &MessagesManager::on_update_dialog_message_ttl_setting,
DialogId(secret_chat_id), MessageTtlSetting(c->ttl));
send_closure_later(G()->messages_manager(), &MessagesManager::on_update_dialog_message_ttl,
DialogId(secret_chat_id), MessageTtl(c->ttl));
c->is_ttl_changed = false;
}
}
@ -10359,11 +10368,11 @@ void ContactsManager::on_get_user_full(tl_object_ptr<telegram_api::userFull> &&u
td_->messages_manager_->on_update_dialog_has_scheduled_server_messages(
DialogId(user_id), (user->flags_ & USER_FULL_FLAG_HAS_SCHEDULED_MESSAGES) != 0);
{
MessageTtlSetting message_ttl_setting;
MessageTtl message_ttl;
if ((user->flags_ & USER_FULL_FLAG_HAS_MESSAGE_TTL) != 0) {
message_ttl_setting = MessageTtlSetting(user->ttl_period_);
message_ttl = MessageTtl(user->ttl_period_);
}
td_->messages_manager_->on_update_dialog_message_ttl_setting(DialogId(user_id), message_ttl_setting);
td_->messages_manager_->on_update_dialog_message_ttl(DialogId(user_id), message_ttl);
}
UserFull *user_full = add_user_full(user_id);
@ -10636,11 +10645,11 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
default_join_group_call_as_dialog_id, false);
}
{
MessageTtlSetting message_ttl_setting;
MessageTtl message_ttl;
if ((chat->flags_ & CHAT_FULL_FLAG_HAS_MESSAGE_TTL) != 0) {
message_ttl_setting = MessageTtlSetting(chat->ttl_period_);
message_ttl = MessageTtl(chat->ttl_period_);
}
td_->messages_manager_->on_update_dialog_message_ttl_setting(DialogId(chat_id), message_ttl_setting);
td_->messages_manager_->on_update_dialog_message_ttl(DialogId(chat_id), message_ttl);
}
ChatFull *chat_full = add_chat_full(chat_id);
@ -10713,11 +10722,11 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
std::move(channel->recent_requesters_));
{
MessageTtlSetting message_ttl_setting;
MessageTtl message_ttl;
if ((channel->flags_ & CHANNEL_FULL_FLAG_HAS_MESSAGE_TTL) != 0) {
message_ttl_setting = MessageTtlSetting(channel->ttl_period_);
message_ttl = MessageTtl(channel->ttl_period_);
}
td_->messages_manager_->on_update_dialog_message_ttl_setting(DialogId(channel_id), message_ttl_setting);
td_->messages_manager_->on_update_dialog_message_ttl(DialogId(channel_id), message_ttl);
}
auto c = get_channel(channel_id);
@ -14457,6 +14466,10 @@ bool ContactsManager::is_channel_public(const Channel *c) {
ContactsManager::ChannelType ContactsManager::get_channel_type(ChannelId channel_id) const {
auto c = get_channel(channel_id);
if (c == nullptr) {
auto min_channel = get_min_channel(channel_id);
if (min_channel != nullptr) {
return min_channel->is_megagroup_ ? ChannelType::Megagroup : ChannelType::Broadcast;
}
return ChannelType::Unknown;
}
return get_channel_type(c);
@ -14569,6 +14582,21 @@ bool ContactsManager::have_min_channel(ChannelId channel_id) const {
return min_channels_.count(channel_id) > 0;
}
const MinChannel *ContactsManager::get_min_channel(ChannelId channel_id) const {
auto it = min_channels_.find(channel_id);
if (it == min_channels_.end()) {
return nullptr;
}
return it->second.get();
}
void ContactsManager::add_min_channel(ChannelId channel_id, const MinChannel &min_channel) {
if (have_channel(channel_id) || have_min_channel(channel_id)) {
return;
}
min_channels_[channel_id] = td::make_unique<MinChannel>(min_channel);
}
const ContactsManager::Channel *ContactsManager::get_channel(ChannelId channel_id) const {
auto p = channels_.find(channel_id);
if (p == channels_.end()) {
@ -15602,8 +15630,8 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char
Channel *c = get_channel_force(channel_id);
LOG(ERROR) << "Receive empty " << to_string(channel) << " from " << source << ", have "
<< to_string(get_supergroup_object(channel_id, c));
if (c == nullptr) {
min_channels_.insert(channel_id);
if (c == nullptr && !have_min_channel(channel_id)) {
min_channels_[channel_id] = td::make_unique<MinChannel>();
}
return;
}
@ -15671,7 +15699,6 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char
}();
if (is_min) {
// TODO there can be better support for min channels
Channel *c = get_channel_force(channel_id);
if (c != nullptr) {
LOG(DEBUG) << "Receive known min " << channel_id;
@ -15706,7 +15733,16 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char
update_channel(c, channel_id);
} else {
min_channels_.insert(channel_id);
auto min_channel = td::make_unique<MinChannel>();
min_channel->photo_ =
get_dialog_photo(td_->file_manager_.get(), DialogId(channel_id), access_hash, std::move(channel.photo_));
if (td_->auth_manager_->is_bot()) {
min_channel->photo_.minithumbnail.clear();
}
min_channel->title_ = std::move(channel.title_);
min_channel->is_megagroup_ = is_megagroup;
min_channels_[channel_id] = std::move(min_channel);
}
return;
}
@ -15806,8 +15842,8 @@ void ContactsManager::on_chat_update(telegram_api::channelForbidden &channel, co
Channel *c = get_channel_force(channel_id);
LOG(ERROR) << "Receive empty " << to_string(channel) << " from " << source << ", have "
<< to_string(get_supergroup_object(channel_id, c));
if (c == nullptr) {
min_channels_.insert(channel_id);
if (c == nullptr && !have_min_channel(channel_id)) {
min_channels_[channel_id] = td::make_unique<MinChannel>();
}
return;
}
@ -16131,15 +16167,21 @@ tl_object_ptr<td_api::basicGroupFullInfo> ContactsManager::get_basic_group_full_
}
td_api::object_ptr<td_api::updateSupergroup> ContactsManager::get_update_unknown_supergroup_object(
ChannelId channel_id) {
ChannelId channel_id) const {
auto min_channel = get_min_channel(channel_id);
return td_api::make_object<td_api::updateSupergroup>(td_api::make_object<td_api::supergroup>(
channel_id.get(), string(), 0, DialogParticipantStatus::Banned(0).get_chat_member_status_object(), 0, false,
false, false, false, true, false, false, string(), false, false));
false, false, false, min_channel == nullptr ? true : !min_channel->is_megagroup_, false, false, string(), false,
false));
}
int64 ContactsManager::get_supergroup_id_object(ChannelId channel_id, const char *source) const {
if (channel_id.is_valid() && get_channel(channel_id) == nullptr && unknown_channels_.count(channel_id) == 0) {
LOG(ERROR) << "Have no info about " << channel_id << " received from " << source;
if (have_min_channel(channel_id)) {
LOG(INFO) << "Have only min " << channel_id << " received from " << source;
} else {
LOG(ERROR) << "Have no info about " << channel_id << " received from " << source;
}
unknown_channels_.insert(channel_id);
send_closure(G()->td(), &Td::send_update, get_update_unknown_supergroup_object(channel_id));
}

View File

@ -55,6 +55,8 @@ namespace td {
struct BinlogEvent;
struct MinChannel;
class Td;
class ContactsManager final : public Actor {
@ -492,8 +494,11 @@ class ContactsManager final : public Actor {
DialogParticipantStatus get_chat_permissions(ChatId chat_id) const;
bool is_appointed_chat_administrator(ChatId chat_id) const;
bool have_channel(ChannelId channel_id) const;
bool have_min_channel(ChannelId channel_id) const;
const MinChannel *get_min_channel(ChannelId channel_id) const;
void add_min_channel(ChannelId channel_id, const MinChannel &min_channel);
bool have_channel(ChannelId channel_id) const;
bool have_channel_force(ChannelId channel_id);
bool get_channel(ChannelId channel_id, int left_tries, Promise<Unit> &&promise);
void reload_channel(ChannelId channel_id, Promise<Unit> &&promise);
@ -1520,7 +1525,7 @@ class ContactsManager final : public Actor {
tl_object_ptr<td_api::basicGroupFullInfo> get_basic_group_full_info_object(const ChatFull *chat_full) const;
static td_api::object_ptr<td_api::updateSupergroup> get_update_unknown_supergroup_object(ChannelId channel_id);
td_api::object_ptr<td_api::updateSupergroup> get_update_unknown_supergroup_object(ChannelId channel_id) const;
static tl_object_ptr<td_api::supergroup> get_supergroup_object(ChannelId channel_id, const Channel *c);
@ -1651,7 +1656,7 @@ class ContactsManager final : public Actor {
mutable std::unordered_set<ChatId, ChatIdHash> unknown_chats_;
std::unordered_map<ChatId, FileSourceId, ChatIdHash> chat_full_file_source_ids_;
std::unordered_set<ChannelId, ChannelIdHash> min_channels_;
std::unordered_map<ChannelId, unique_ptr<MinChannel>, ChannelIdHash> min_channels_;
std::unordered_map<ChannelId, unique_ptr<Channel>, ChannelIdHash> channels_;
std::unordered_map<ChannelId, unique_ptr<ChannelFull>, ChannelIdHash> channels_full_;
mutable std::unordered_set<ChannelId, ChannelIdHash> unknown_channels_;

View File

@ -67,6 +67,10 @@ bool resolve_dependencies_force(Td *td, const Dependencies &dependencies, const
}
for (auto channel_id : dependencies.channel_ids) {
if (channel_id.is_valid() && !td->contacts_manager_->have_channel_force(channel_id)) {
if (td->contacts_manager_->have_min_channel(channel_id)) {
LOG(INFO) << "Can't find " << channel_id << " from " << source << ", but have it as a min-channel";
continue;
}
LOG(ERROR) << "Can't find " << channel_id << " from " << source;
success = false;
}

View File

@ -240,9 +240,9 @@ void DeviceTokenManager::register_device(tl_object_ptr<td_api::DeviceToken> devi
return promise.set_error(Status::Error(400, "Invalid user_id among other user_ids"));
}
}
auto input_user_ids = UserId::get_input_user_ids(other_user_ids);
auto &info = tokens_[token_type];
info.net_query_id = 0;
if (token.empty()) {
if (info.token.empty()) {
// already unregistered
@ -251,10 +251,17 @@ void DeviceTokenManager::register_device(tl_object_ptr<td_api::DeviceToken> devi
info.state = TokenInfo::State::Unregister;
} else {
if ((info.state == TokenInfo::State::Reregister || info.state == TokenInfo::State::Sync) && info.token == token &&
info.other_user_ids == input_user_ids && info.is_app_sandbox == is_app_sandbox && encrypt == info.encrypt) {
int64 push_token_id = encrypt ? info.encryption_key_id : G()->get_my_id();
return promise.set_value(td_api::make_object<td_api::pushReceiverId>(push_token_id));
}
info.state = TokenInfo::State::Register;
info.token = std::move(token);
}
info.other_user_ids = UserId::get_input_user_ids(other_user_ids);
info.net_query_id = 0;
info.other_user_ids = std::move(input_user_ids);
info.is_app_sandbox = is_app_sandbox;
if (encrypt != info.encrypt) {
if (encrypt) {

View File

@ -83,7 +83,7 @@ Status init_dialog_db(SqliteDb &db, int32 version, KeyValueSyncInterface &binlog
if (version < static_cast<int32>(DbVersion::StorePinnedDialogsInBinlog)) {
// 9221294780217032704 == get_dialog_order(Auto(), MIN_PINNED_DIALOG_DATE - 1)
TRY_RESULT(get_pinned_dialogs_stmt,
db.get_statement("SELECT dialog_id FROM dialogs WHERE folder_id == ?1 AND dialog_order > "
db.get_statement("SELECT dialog_id FROM dialogs WHERE folder_id = ?1 AND dialog_order > "
"9221294780217032704 ORDER BY dialog_order DESC, dialog_id DESC"));
for (auto folder_id = 0; folder_id < 2; folder_id++) {
vector<string> pinned_dialog_ids;
@ -137,7 +137,7 @@ class DialogDbImpl final : public DialogDbSyncInterface {
TRY_RESULT_ASSIGN(
get_dialogs_stmt_,
db_.get_statement("SELECT data, dialog_id, dialog_order FROM dialogs WHERE "
"folder_id == ?1 AND (dialog_order < ?2 OR (dialog_order = ?2 AND dialog_id < ?3)) ORDER "
"folder_id = ?1 AND (dialog_order < ?2 OR (dialog_order = ?2 AND dialog_id < ?3)) ORDER "
"BY dialog_order DESC, dialog_id DESC LIMIT ?4"));
TRY_RESULT_ASSIGN(
get_notification_groups_by_last_notification_date_stmt_,
@ -252,6 +252,8 @@ class DialogDbImpl final : public DialogDbSyncInterface {
get_dialogs_stmt_.bind_int32(4, limit).ensure();
DialogDbGetDialogsResult result;
result.next_dialog_id = dialog_id;
result.next_order = order;
TRY_STATUS(get_dialogs_stmt_.step());
while (get_dialogs_stmt_.has_row()) {
BufferSlice data(get_dialogs_stmt_.view_blob(0));

View File

@ -17,7 +17,7 @@
#include "td/telegram/InputGroupCallId.h"
#include "td/telegram/MessageSender.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/MessageTtlSetting.h"
#include "td/telegram/MessageTtl.h"
#include "td/telegram/StickersManager.h"
#include "td/telegram/Td.h"
#include "td/telegram/telegram_api.h"
@ -30,7 +30,8 @@
namespace td {
static td_api::object_ptr<td_api::ChatEventAction> get_chat_event_action_object(
Td *td, ChannelId channel_id, tl_object_ptr<telegram_api::ChannelAdminLogEventAction> &&action_ptr) {
Td *td, ChannelId channel_id, tl_object_ptr<telegram_api::ChannelAdminLogEventAction> &&action_ptr,
DialogId &actor_dialog_id) {
CHECK(action_ptr != nullptr);
switch (action_ptr->get_id()) {
case telegram_api::channelAdminLogEventActionParticipantJoin::ID:
@ -150,8 +151,9 @@ static td_api::object_ptr<td_api::ChatEventAction> get_chat_event_action_object(
}
case telegram_api::channelAdminLogEventActionUpdatePinned::ID: {
auto action = move_tl_object_as<telegram_api::channelAdminLogEventActionUpdatePinned>(action_ptr);
auto message =
td->messages_manager_->get_dialog_event_log_message_object(DialogId(channel_id), std::move(action->message_));
DialogId sender_dialog_id;
auto message = td->messages_manager_->get_dialog_event_log_message_object(
DialogId(channel_id), std::move(action->message_), sender_dialog_id);
if (message == nullptr) {
return nullptr;
}
@ -166,19 +168,24 @@ static td_api::object_ptr<td_api::ChatEventAction> get_chat_event_action_object(
}
case telegram_api::channelAdminLogEventActionEditMessage::ID: {
auto action = move_tl_object_as<telegram_api::channelAdminLogEventActionEditMessage>(action_ptr);
auto old_message = td->messages_manager_->get_dialog_event_log_message_object(DialogId(channel_id),
std::move(action->prev_message_));
auto new_message = td->messages_manager_->get_dialog_event_log_message_object(DialogId(channel_id),
std::move(action->new_message_));
DialogId old_sender_dialog_id;
auto old_message = td->messages_manager_->get_dialog_event_log_message_object(
DialogId(channel_id), std::move(action->prev_message_), old_sender_dialog_id);
DialogId new_sender_dialog_id;
auto new_message = td->messages_manager_->get_dialog_event_log_message_object(
DialogId(channel_id), std::move(action->new_message_), new_sender_dialog_id);
if (old_message == nullptr || new_message == nullptr) {
return nullptr;
}
if (old_sender_dialog_id == new_sender_dialog_id) {
actor_dialog_id = old_sender_dialog_id;
}
return td_api::make_object<td_api::chatEventMessageEdited>(std::move(old_message), std::move(new_message));
}
case telegram_api::channelAdminLogEventActionStopPoll::ID: {
auto action = move_tl_object_as<telegram_api::channelAdminLogEventActionStopPoll>(action_ptr);
auto message =
td->messages_manager_->get_dialog_event_log_message_object(DialogId(channel_id), std::move(action->message_));
auto message = td->messages_manager_->get_dialog_event_log_message_object(
DialogId(channel_id), std::move(action->message_), actor_dialog_id);
if (message == nullptr) {
return nullptr;
}
@ -186,8 +193,8 @@ static td_api::object_ptr<td_api::ChatEventAction> get_chat_event_action_object(
}
case telegram_api::channelAdminLogEventActionDeleteMessage::ID: {
auto action = move_tl_object_as<telegram_api::channelAdminLogEventActionDeleteMessage>(action_ptr);
auto message =
td->messages_manager_->get_dialog_event_log_message_object(DialogId(channel_id), std::move(action->message_));
auto message = td->messages_manager_->get_dialog_event_log_message_object(
DialogId(channel_id), std::move(action->message_), actor_dialog_id);
if (message == nullptr) {
return nullptr;
}
@ -287,7 +294,7 @@ static td_api::object_ptr<td_api::ChatEventAction> get_chat_event_action_object(
if (!input_group_call_id.is_valid()) {
return nullptr;
}
return td_api::make_object<td_api::chatEventVideoChatDiscarded>(
return td_api::make_object<td_api::chatEventVideoChatEnded>(
td->group_call_manager_->get_group_call_id(input_group_call_id, DialogId(channel_id)).get());
}
case telegram_api::channelAdminLogEventActionParticipantMute::ID: {
@ -324,10 +331,10 @@ static td_api::object_ptr<td_api::ChatEventAction> get_chat_event_action_object(
}
case telegram_api::channelAdminLogEventActionChangeHistoryTTL::ID: {
auto action = move_tl_object_as<telegram_api::channelAdminLogEventActionChangeHistoryTTL>(action_ptr);
auto old_value = MessageTtlSetting(clamp(action->prev_value_, 0, 86400 * 366));
auto new_value = MessageTtlSetting(clamp(action->new_value_, 0, 86400 * 366));
return td_api::make_object<td_api::chatEventMessageTtlSettingChanged>(old_value.get_message_ttl_setting_object(),
new_value.get_message_ttl_setting_object());
auto old_value = MessageTtl(clamp(action->prev_value_, 0, 86400 * 366));
auto new_value = MessageTtl(clamp(action->new_value_, 0, 86400 * 366));
return td_api::make_object<td_api::chatEventMessageTtlChanged>(old_value.get_message_ttl_object(),
new_value.get_message_ttl_object());
}
case telegram_api::channelAdminLogEventActionToggleNoForwards::ID: {
auto action = move_tl_object_as<telegram_api::channelAdminLogEventActionToggleNoForwards>(action_ptr);
@ -394,13 +401,20 @@ class GetChannelAdminLogQuery final : public Td::ResultHandler {
}
LOG_IF(ERROR, !td_->contacts_manager_->have_user(user_id)) << "Have no info about " << user_id;
auto action = get_chat_event_action_object(td_, channel_id_, std::move(event->action_));
DialogId actor_dialog_id;
auto action = get_chat_event_action_object(td_, channel_id_, std::move(event->action_), actor_dialog_id);
if (action == nullptr) {
continue;
}
result->events_.push_back(td_api::make_object<td_api::chatEvent>(
event->id_, event->date_, td_->contacts_manager_->get_user_id_object(user_id, "chatEvent"),
std::move(action)));
if (user_id == ContactsManager::get_channel_bot_user_id() && actor_dialog_id.is_valid() &&
actor_dialog_id.get_type() != DialogType::User) {
user_id = UserId();
} else {
actor_dialog_id = DialogId();
}
auto actor = get_message_sender_object_const(td_, user_id, actor_dialog_id, "GetChannelAdminLogQuery");
result->events_.push_back(
td_api::make_object<td_api::chatEvent>(event->id_, event->date_, std::move(actor), std::move(action)));
}
promise_.set_value(std::move(result));

View File

@ -131,6 +131,44 @@ string DialogFilter::get_icon_name() const {
return string();
}
string DialogFilter::get_chosen_or_default_icon_name() const {
auto icon_name = get_icon_name();
if (!icon_name.empty()) {
return icon_name;
}
if (!pinned_dialog_ids.empty() || !included_dialog_ids.empty() || !excluded_dialog_ids.empty()) {
return "Custom";
}
if (include_contacts || include_non_contacts) {
if (!include_bots && !include_groups && !include_channels) {
return "Private";
}
} else {
if (!include_bots && !include_channels) {
if (!include_groups) {
// just in case
return "Custom";
}
return "Groups";
}
if (!include_bots && !include_groups) {
return "Channels";
}
if (!include_groups && !include_channels) {
return "Bots";
}
}
if (exclude_read && !exclude_muted) {
return "Unread";
}
if (exclude_muted && !exclude_read) {
return "Unmuted";
}
return "Custom";
}
string DialogFilter::get_default_icon_name(const td_api::chatFilter *filter) {
if (!filter->icon_name_.empty() && !get_emoji_by_icon_name(filter->icon_name_).empty()) {
return filter->icon_name_;
@ -206,7 +244,7 @@ telegram_api::object_ptr<telegram_api::dialogFilter> DialogFilter::get_input_dia
}
td_api::object_ptr<td_api::chatFilterInfo> DialogFilter::get_chat_filter_info_object() const {
return td_api::make_object<td_api::chatFilterInfo>(dialog_filter_id.get(), title, get_icon_name());
return td_api::make_object<td_api::chatFilterInfo>(dialog_filter_id.get(), title, get_chosen_or_default_icon_name());
}
// merges changes from old_server_filter to new_server_filter in old_filter

View File

@ -79,6 +79,8 @@ class DialogFilter {
static std::unordered_map<string, string> icon_name_to_emoji_;
static void init_icon_names();
string get_chosen_or_default_icon_name() const;
};
inline bool operator==(const DialogFilter &lhs, const DialogFilter &rhs) {

View File

@ -3108,6 +3108,7 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo
const Photo *old_photo = &old_->photo;
Photo *new_photo = &new_->photo;
if (old_photo->date != new_photo->date) {
LOG(DEBUG) << "Photo date has changed from " << old_photo->date << " to " << new_photo->date;
is_content_changed = true;
}
if (old_photo->id.get() != new_photo->id.get() || old_->caption != new_->caption) {
@ -3133,6 +3134,7 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo
}
new_photo->photos.push_back(old_photo->photos.back());
need_merge = true;
need_update = true;
} else {
// get sent photo again
if (old_photos_size == 2 + new_photos_size && old_photo->photos[new_photos_size].type == 't') {

View File

@ -1504,7 +1504,7 @@ static bool are_entities_valid(const vector<MessageEntity> &entities) {
return false;
}
if ((nested_entity_type_mask & get_splittable_entities_mask()) != 0) {
// the previous nested entity may be needed to splitted for consistency
// the previous nested entity may be needed to split for consistency
// alternatively, better entity merging needs to be implemented
return false;
}
@ -2595,7 +2595,7 @@ static FormattedText parse_pre_entities_v3(Slice text, vector<MessageEntity> ent
}
// text entities must be valid
// returned entities must be resplitted and fixed
// returned entities must be resplit and fixed
FormattedText parse_markdown_v3(FormattedText text) {
if (text.text.find('`') != string::npos) {
text = parse_pre_entities_v3(text.text, std::move(text.entities));

View File

@ -9,6 +9,7 @@
#include "td/telegram/ContactsManager.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/ServerMessageId.h"
#include "td/telegram/Td.h"
#include "td/utils/algorithm.h"
#include "td/utils/logging.h"
@ -16,7 +17,7 @@
namespace td {
MessageReplyInfo::MessageReplyInfo(tl_object_ptr<telegram_api::messageReplies> &&reply_info, bool is_bot) {
MessageReplyInfo::MessageReplyInfo(Td *td, tl_object_ptr<telegram_api::messageReplies> &&reply_info, bool is_bot) {
if (reply_info == nullptr || is_bot || reply_info->channel_id_ == 777) {
return;
}
@ -41,15 +42,39 @@ MessageReplyInfo::MessageReplyInfo(tl_object_ptr<telegram_api::messageReplies> &
if (is_comment) {
for (const auto &peer : reply_info->recent_repliers_) {
DialogId dialog_id(peer);
if (dialog_id.is_valid()) {
// save all valid dialog_id, despite we can have no info about some of them
recent_replier_dialog_ids.push_back(dialog_id);
} else {
if (!dialog_id.is_valid()) {
LOG(ERROR) << "Receive " << dialog_id << " as a recent replier";
continue;
}
if (td::contains(recent_replier_dialog_ids, dialog_id)) {
LOG(ERROR) << "Receive duplicate " << dialog_id << " as a recent replier";
continue;
}
if (!td->messages_manager_->have_dialog_info(dialog_id)) {
auto dialog_type = dialog_id.get_type();
if (dialog_type == DialogType::User) {
auto replier_user_id = dialog_id.get_user_id();
if (!td->contacts_manager_->have_min_user(replier_user_id)) {
LOG(ERROR) << "Have no info about replied " << replier_user_id;
continue;
}
} else if (dialog_type == DialogType::Channel) {
auto replier_channel_id = dialog_id.get_channel_id();
auto min_channel = td->contacts_manager_->get_min_channel(replier_channel_id);
if (min_channel == nullptr) {
LOG(ERROR) << "Have no info about replied " << replier_channel_id;
continue;
}
replier_min_channels.emplace_back(replier_channel_id, *min_channel);
} else {
LOG(ERROR) << "Have no info about replied " << dialog_id;
continue;
}
}
recent_replier_dialog_ids.push_back(dialog_id);
if (recent_replier_dialog_ids.size() == MAX_RECENT_REPLIERS) {
break;
}
}
if (recent_replier_dialog_ids.size() > MAX_RECENT_REPLIERS) {
recent_replier_dialog_ids.resize(MAX_RECENT_REPLIERS);
}
}
if ((reply_info->flags_ & telegram_api::messageReplies::MAX_ID_MASK) != 0 &&
@ -75,7 +100,8 @@ bool MessageReplyInfo::need_update_to(const MessageReplyInfo &other) const {
return false;
}
return reply_count != other.reply_count || recent_replier_dialog_ids != other.recent_replier_dialog_ids ||
is_comment != other.is_comment || channel_id != other.channel_id;
replier_min_channels.size() != other.replier_min_channels.size() || is_comment != other.is_comment ||
channel_id != other.channel_id;
}
bool MessageReplyInfo::update_max_message_ids(const MessageReplyInfo &other) {
@ -120,6 +146,16 @@ bool MessageReplyInfo::add_reply(DialogId replier_dialog_id, MessageId reply_mes
reply_count += diff;
if (is_comment && replier_dialog_id.is_valid()) {
if (replier_dialog_id.get_type() == DialogType::Channel) {
// the replier_dialog_id is never min, because it is the sender of a message
for (auto it = replier_min_channels.begin(); it != replier_min_channels.end(); ++it) {
if (it->first == replier_dialog_id.get_channel_id()) {
replier_min_channels.erase(it);
break;
}
}
}
td::remove(recent_replier_dialog_ids, replier_dialog_id);
if (diff > 0) {
recent_replier_dialog_ids.insert(recent_replier_dialog_ids.begin(), replier_dialog_id);
@ -140,23 +176,48 @@ bool MessageReplyInfo::add_reply(DialogId replier_dialog_id, MessageId reply_mes
return true;
}
td_api::object_ptr<td_api::messageReplyInfo> MessageReplyInfo::get_message_reply_info_object(
ContactsManager *contacts_manager, const MessagesManager *messages_manager) const {
bool MessageReplyInfo::need_reget(const Td *td) const {
for (auto &dialog_id : recent_replier_dialog_ids) {
if (dialog_id.get_type() != DialogType::User && !td->messages_manager_->have_dialog_info(dialog_id)) {
if (dialog_id.get_type() == DialogType::Channel &&
td->contacts_manager_->have_min_channel(dialog_id.get_channel_id())) {
return false;
}
LOG(INFO) << "Reget a message because of replied " << dialog_id;
return true;
}
}
return false;
}
td_api::object_ptr<td_api::messageReplyInfo> MessageReplyInfo::get_message_reply_info_object(Td *td) const {
if (is_empty()) {
return nullptr;
}
vector<td_api::object_ptr<td_api::MessageSender>> recent_repliers;
for (auto recent_replier_dialog_id : recent_replier_dialog_ids) {
if (recent_replier_dialog_id.get_type() == DialogType::User) {
auto user_id = recent_replier_dialog_id.get_user_id();
if (contacts_manager->have_min_user(user_id)) {
for (auto dialog_id : recent_replier_dialog_ids) {
auto dialog_type = dialog_id.get_type();
if (dialog_type == DialogType::User) {
auto user_id = dialog_id.get_user_id();
if (td->contacts_manager_->have_min_user(user_id)) {
recent_repliers.push_back(td_api::make_object<td_api::messageSenderUser>(
contacts_manager->get_user_id_object(user_id, "get_message_reply_info_object")));
td->contacts_manager_->get_user_id_object(user_id, "get_message_reply_info_object")));
} else {
LOG(ERROR) << "Skip unknown replied " << user_id;
}
} else {
if (messages_manager->have_dialog(recent_replier_dialog_id)) {
recent_repliers.push_back(td_api::make_object<td_api::messageSenderChat>(recent_replier_dialog_id.get()));
if (!td->messages_manager_->have_dialog(dialog_id) &&
(td->messages_manager_->have_dialog_info(dialog_id) ||
(dialog_type == DialogType::Channel &&
td->contacts_manager_->have_min_channel(dialog_id.get_channel_id())))) {
LOG(INFO) << "Force creation of " << dialog_id;
td->messages_manager_->force_create_dialog(dialog_id, "get_message_reply_info_object", true);
}
if (td->messages_manager_->have_dialog(dialog_id)) {
recent_repliers.push_back(td_api::make_object<td_api::messageSenderChat>(dialog_id.get()));
} else {
LOG(ERROR) << "Skip unknown replied " << dialog_id;
}
}
}

View File

@ -9,23 +9,25 @@
#include "td/telegram/ChannelId.h"
#include "td/telegram/DialogId.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/MinChannel.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/common.h"
#include "td/utils/StringBuilder.h"
#include "td/utils/tl_helpers.h"
#include <utility>
namespace td {
class ContactsManager;
class MessagesManager;
class Td;
struct MessageReplyInfo {
int32 reply_count = -1;
int32 pts = -1;
vector<DialogId> recent_replier_dialog_ids; // comments only
ChannelId channel_id; // comments only
vector<DialogId> recent_replier_dialog_ids; // comments only
vector<std::pair<ChannelId, MinChannel>> replier_min_channels; // comments only
ChannelId channel_id; // comments only
MessageId max_message_id;
MessageId last_read_inbox_message_id;
MessageId last_read_outbox_message_id;
@ -35,7 +37,7 @@ struct MessageReplyInfo {
MessageReplyInfo() = default;
MessageReplyInfo(tl_object_ptr<telegram_api::messageReplies> &&reply_info, bool is_bot);
MessageReplyInfo(Td *td, tl_object_ptr<telegram_api::messageReplies> &&reply_info, bool is_bot);
bool is_empty() const {
return reply_count < 0;
@ -50,83 +52,15 @@ struct MessageReplyInfo {
bool add_reply(DialogId replier_dialog_id, MessageId reply_message_id, int diff);
td_api::object_ptr<td_api::messageReplyInfo> get_message_reply_info_object(
ContactsManager *contacts_manager, const MessagesManager *messages_manager) const;
bool need_reget(const Td *td) const;
td_api::object_ptr<td_api::messageReplyInfo> get_message_reply_info_object(Td *td) const;
template <class StorerT>
void store(StorerT &storer) const {
CHECK(!is_empty());
bool has_recent_replier_dialog_ids = !recent_replier_dialog_ids.empty();
bool has_channel_id = channel_id.is_valid();
bool has_max_message_id = max_message_id.is_valid();
bool has_last_read_inbox_message_id = last_read_inbox_message_id.is_valid();
bool has_last_read_outbox_message_id = last_read_outbox_message_id.is_valid();
BEGIN_STORE_FLAGS();
STORE_FLAG(is_comment);
STORE_FLAG(has_recent_replier_dialog_ids);
STORE_FLAG(has_channel_id);
STORE_FLAG(has_max_message_id);
STORE_FLAG(has_last_read_inbox_message_id);
STORE_FLAG(has_last_read_outbox_message_id);
END_STORE_FLAGS();
td::store(reply_count, storer);
td::store(pts, storer);
if (has_recent_replier_dialog_ids) {
td::store(recent_replier_dialog_ids, storer);
}
if (has_channel_id) {
td::store(channel_id, storer);
}
if (has_max_message_id) {
td::store(max_message_id, storer);
}
if (has_last_read_inbox_message_id) {
td::store(last_read_inbox_message_id, storer);
}
if (has_last_read_outbox_message_id) {
td::store(last_read_outbox_message_id, storer);
}
}
void store(StorerT &storer) const;
template <class ParserT>
void parse(ParserT &parser) {
bool has_recent_replier_dialog_ids;
bool has_channel_id;
bool has_max_message_id;
bool has_last_read_inbox_message_id;
bool has_last_read_outbox_message_id;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(is_comment);
PARSE_FLAG(has_recent_replier_dialog_ids);
PARSE_FLAG(has_channel_id);
PARSE_FLAG(has_max_message_id);
PARSE_FLAG(has_last_read_inbox_message_id);
PARSE_FLAG(has_last_read_outbox_message_id);
END_PARSE_FLAGS();
td::parse(reply_count, parser);
td::parse(pts, parser);
if (has_recent_replier_dialog_ids) {
td::parse(recent_replier_dialog_ids, parser);
}
if (has_channel_id) {
td::parse(channel_id, parser);
}
if (has_max_message_id) {
td::parse(max_message_id, parser);
}
if (has_last_read_inbox_message_id) {
td::parse(last_read_inbox_message_id, parser);
}
if (has_last_read_outbox_message_id) {
td::parse(last_read_outbox_message_id, parser);
}
if (channel_id.get() == 777) {
*this = MessageReplyInfo();
}
if (recent_replier_dialog_ids.size() > MAX_RECENT_REPLIERS) {
recent_replier_dialog_ids.resize(MAX_RECENT_REPLIERS);
}
}
void parse(ParserT &parser);
};
StringBuilder &operator<<(StringBuilder &string_builder, const MessageReplyInfo &reply_info);

View File

@ -0,0 +1,103 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once
#include "td/telegram/MessageReplyInfo.h"
#include "td/telegram/MinChannel.hpp"
#include "td/utils/common.h"
#include "td/utils/tl_helpers.h"
namespace td {
template <class StorerT>
void MessageReplyInfo::store(StorerT &storer) const {
CHECK(!is_empty());
bool has_recent_replier_dialog_ids = !recent_replier_dialog_ids.empty();
bool has_channel_id = channel_id.is_valid();
bool has_max_message_id = max_message_id.is_valid();
bool has_last_read_inbox_message_id = last_read_inbox_message_id.is_valid();
bool has_last_read_outbox_message_id = last_read_outbox_message_id.is_valid();
bool has_replier_min_channels = !replier_min_channels.empty();
BEGIN_STORE_FLAGS();
STORE_FLAG(is_comment);
STORE_FLAG(has_recent_replier_dialog_ids);
STORE_FLAG(has_channel_id);
STORE_FLAG(has_max_message_id);
STORE_FLAG(has_last_read_inbox_message_id);
STORE_FLAG(has_last_read_outbox_message_id);
STORE_FLAG(has_replier_min_channels);
END_STORE_FLAGS();
td::store(reply_count, storer);
td::store(pts, storer);
if (has_recent_replier_dialog_ids) {
td::store(recent_replier_dialog_ids, storer);
}
if (has_channel_id) {
td::store(channel_id, storer);
}
if (has_max_message_id) {
td::store(max_message_id, storer);
}
if (has_last_read_inbox_message_id) {
td::store(last_read_inbox_message_id, storer);
}
if (has_last_read_outbox_message_id) {
td::store(last_read_outbox_message_id, storer);
}
if (has_replier_min_channels) {
td::store(replier_min_channels, storer);
}
}
template <class ParserT>
void MessageReplyInfo::parse(ParserT &parser) {
bool has_recent_replier_dialog_ids;
bool has_channel_id;
bool has_max_message_id;
bool has_last_read_inbox_message_id;
bool has_last_read_outbox_message_id;
bool has_replier_min_channels;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(is_comment);
PARSE_FLAG(has_recent_replier_dialog_ids);
PARSE_FLAG(has_channel_id);
PARSE_FLAG(has_max_message_id);
PARSE_FLAG(has_last_read_inbox_message_id);
PARSE_FLAG(has_last_read_outbox_message_id);
PARSE_FLAG(has_replier_min_channels);
END_PARSE_FLAGS();
td::parse(reply_count, parser);
td::parse(pts, parser);
if (has_recent_replier_dialog_ids) {
td::parse(recent_replier_dialog_ids, parser);
}
if (has_channel_id) {
td::parse(channel_id, parser);
}
if (has_max_message_id) {
td::parse(max_message_id, parser);
}
if (has_last_read_inbox_message_id) {
td::parse(last_read_inbox_message_id, parser);
}
if (has_last_read_outbox_message_id) {
td::parse(last_read_outbox_message_id, parser);
}
if (has_replier_min_channels) {
td::parse(replier_min_channels, parser);
}
if (channel_id.get() == 777) {
*this = MessageReplyInfo();
}
if (recent_replier_dialog_ids.size() > MAX_RECENT_REPLIERS) {
recent_replier_dialog_ids.resize(MAX_RECENT_REPLIERS);
}
}
} // namespace td

View File

@ -0,0 +1,27 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "td/telegram/MessageTtl.h"
namespace td {
bool MessageTtl::is_empty() const {
return period_ == 0;
}
int32 MessageTtl::get_message_ttl_object() const {
return period_;
}
bool operator==(const MessageTtl &lhs, const MessageTtl &rhs) {
return lhs.period_ == rhs.period_;
}
StringBuilder &operator<<(StringBuilder &string_builder, const MessageTtl &message_ttl) {
return string_builder << "MessageTtl[" << message_ttl.period_ << "]";
}
} // namespace td

View File

@ -14,43 +14,43 @@
namespace td {
class MessageTtlSetting {
int32 ttl_period_ = 0;
class MessageTtl {
int32 period_ = 0;
friend StringBuilder &operator<<(StringBuilder &string_builder, const MessageTtlSetting &message_ttl_setting);
friend StringBuilder &operator<<(StringBuilder &string_builder, const MessageTtl &message_ttl);
friend bool operator==(const MessageTtlSetting &lhs, const MessageTtlSetting &rhs);
friend bool operator==(const MessageTtl &lhs, const MessageTtl &rhs);
public:
MessageTtlSetting() = default;
MessageTtl() = default;
template <class T, typename = std::enable_if_t<std::is_convertible<T, int32>::value>>
MessageTtlSetting(T ttl_period) = delete;
MessageTtl(T period) = delete;
explicit MessageTtlSetting(int32 ttl_period) : ttl_period_(ttl_period) {
explicit MessageTtl(int32 period) : period_(period) {
}
bool is_empty() const;
int32 get_message_ttl_setting_object() const;
int32 get_message_ttl_object() const;
template <class StorerT>
void store(StorerT &storer) const {
td::store(ttl_period_, storer);
td::store(period_, storer);
}
template <class ParserT>
void parse(ParserT &parser) {
td::parse(ttl_period_, parser);
td::parse(period_, parser);
}
};
bool operator==(const MessageTtlSetting &lhs, const MessageTtlSetting &rhs);
bool operator==(const MessageTtl &lhs, const MessageTtl &rhs);
inline bool operator!=(const MessageTtlSetting &lhs, const MessageTtlSetting &rhs) {
inline bool operator!=(const MessageTtl &lhs, const MessageTtl &rhs) {
return !(lhs == rhs);
}
StringBuilder &operator<<(StringBuilder &string_builder, const MessageTtlSetting &message_ttl_setting);
StringBuilder &operator<<(StringBuilder &string_builder, const MessageTtl &message_ttl);
} // namespace td

View File

@ -1,27 +0,0 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "td/telegram/MessageTtlSetting.h"
namespace td {
bool MessageTtlSetting::is_empty() const {
return ttl_period_ == 0;
}
int32 MessageTtlSetting::get_message_ttl_setting_object() const {
return ttl_period_;
}
bool operator==(const MessageTtlSetting &lhs, const MessageTtlSetting &rhs) {
return lhs.ttl_period_ == rhs.ttl_period_;
}
StringBuilder &operator<<(StringBuilder &string_builder, const MessageTtlSetting &message_ttl_setting) {
return string_builder << "MessageTtlSetting[" << message_ttl_setting.ttl_period_ << "]";
}
} // namespace td

View File

@ -192,7 +192,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
TRY_RESULT_ASSIGN(delete_all_dialog_messages_stmt_,
db_.get_statement("DELETE FROM messages WHERE dialog_id = ?1 AND message_id <= ?2"));
TRY_RESULT_ASSIGN(delete_dialog_messages_by_sender_stmt_,
db_.get_statement("DELETE FROM messages WHERE dialog_id = ?1 AND sender_user_id == ?2"));
db_.get_statement("DELETE FROM messages WHERE dialog_id = ?1 AND sender_user_id = ?2"));
TRY_RESULT_ASSIGN(
get_message_stmt_,
@ -665,17 +665,19 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
stmt.step().ensure();
}
int32 limit = min(query.limit, static_cast<int32>(message_ids.size()));
double delta = static_cast<double>(message_ids.size()) / limit;
MessagesDbMessagePositions positions;
positions.total_count = static_cast<int32>(message_ids.size());
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.positions.push_back(MessagesDbMessagePosition{position, date, message_id});
int32 limit = min(query.limit, static_cast<int32>(message_ids.size()));
if (limit > 0) {
double delta = static_cast<double>(message_ids.size()) / limit;
positions.total_count = static_cast<int32>(message_ids.size());
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.positions.push_back(MessagesDbMessagePosition{position, date, message_id});
}
}
return positions;
}

View File

@ -34,6 +34,7 @@
#include "td/telegram/MessageContent.h"
#include "td/telegram/MessageEntity.h"
#include "td/telegram/MessageEntity.hpp"
#include "td/telegram/MessageReplyInfo.hpp"
#include "td/telegram/MessagesDb.h"
#include "td/telegram/MessageSender.h"
#include "td/telegram/misc.h"
@ -5298,7 +5299,7 @@ void MessagesManager::Dialog::store(StorerT &storer) const {
bool has_pending_read_channel_inbox = pending_read_channel_inbox_pts != 0;
bool has_last_yet_unsent_message = last_message_id.is_valid() && last_message_id.is_yet_unsent();
bool has_active_group_call_id = active_group_call_id.is_valid();
bool has_message_ttl_setting = !message_ttl_setting.is_empty();
bool has_message_ttl = !message_ttl.is_empty();
bool has_default_join_group_call_as_dialog_id = default_join_group_call_as_dialog_id.is_valid();
bool store_has_bots = dialog_type == DialogType::Chat || dialog_type == DialogType::Channel;
bool has_theme_name = !theme_name.empty();
@ -5365,8 +5366,8 @@ void MessagesManager::Dialog::store(StorerT &storer) const {
STORE_FLAG(is_group_call_empty);
STORE_FLAG(has_active_group_call_id);
STORE_FLAG(false); // action_bar->can_invite_members
STORE_FLAG(has_message_ttl_setting);
STORE_FLAG(is_message_ttl_setting_inited);
STORE_FLAG(has_message_ttl);
STORE_FLAG(is_message_ttl_inited);
STORE_FLAG(has_default_join_group_call_as_dialog_id);
STORE_FLAG(store_has_bots ? has_bots : false);
STORE_FLAG(store_has_bots ? is_has_bots_inited : false);
@ -5466,8 +5467,8 @@ void MessagesManager::Dialog::store(StorerT &storer) const {
if (has_active_group_call_id) {
store(active_group_call_id, storer);
}
if (has_message_ttl_setting) {
store(message_ttl_setting, storer);
if (has_message_ttl) {
store(message_ttl, storer);
}
if (has_default_join_group_call_as_dialog_id) {
store(default_join_group_call_as_dialog_id, storer);
@ -5515,7 +5516,7 @@ void MessagesManager::Dialog::parse(ParserT &parser) {
bool has_folder_id = false;
bool has_pending_read_channel_inbox = false;
bool has_active_group_call_id = false;
bool has_message_ttl_setting = false;
bool has_message_ttl = false;
bool has_default_join_group_call_as_dialog_id = false;
bool has_theme_name = false;
bool has_flags3 = false;
@ -5589,8 +5590,8 @@ void MessagesManager::Dialog::parse(ParserT &parser) {
PARSE_FLAG(is_group_call_empty);
PARSE_FLAG(has_active_group_call_id);
PARSE_FLAG(action_bar_can_invite_members);
PARSE_FLAG(has_message_ttl_setting);
PARSE_FLAG(is_message_ttl_setting_inited);
PARSE_FLAG(has_message_ttl);
PARSE_FLAG(is_message_ttl_inited);
PARSE_FLAG(has_default_join_group_call_as_dialog_id);
PARSE_FLAG(has_bots);
PARSE_FLAG(is_has_bots_inited);
@ -5609,7 +5610,7 @@ void MessagesManager::Dialog::parse(ParserT &parser) {
is_is_blocked_inited = false;
has_active_group_call = false;
is_group_call_empty = false;
is_message_ttl_setting_inited = false;
is_message_ttl_inited = false;
has_bots = false;
is_has_bots_inited = false;
is_theme_name_inited = false;
@ -5744,8 +5745,8 @@ void MessagesManager::Dialog::parse(ParserT &parser) {
if (has_active_group_call_id) {
parse(active_group_call_id, parser);
}
if (has_message_ttl_setting) {
parse(message_ttl_setting, parser);
if (has_message_ttl) {
parse(message_ttl, parser);
}
if (has_default_join_group_call_as_dialog_id) {
parse(default_join_group_call_as_dialog_id, parser);
@ -6844,7 +6845,7 @@ void MessagesManager::update_message_interaction_info(FullMessageId full_message
forward_count = m->forward_count;
}
bool is_empty_reply_info = reply_info == nullptr;
MessageReplyInfo new_reply_info(std::move(reply_info), td_->auth_manager_->is_bot());
MessageReplyInfo new_reply_info(td_, std::move(reply_info), td_->auth_manager_->is_bot());
if (new_reply_info.is_empty() && !is_empty_reply_info) {
has_reply_info = false;
}
@ -6926,7 +6927,7 @@ td_api::object_ptr<td_api::messageInteractionInfo> MessagesManager::get_message_
td_api::object_ptr<td_api::messageReplyInfo> reply_info;
if (is_visible_reply_info) {
reply_info = m->reply_info.get_message_reply_info_object(td_->contacts_manager_.get(), this);
reply_info = m->reply_info.get_message_reply_info_object(td_);
CHECK(reply_info != nullptr);
}
@ -11503,8 +11504,10 @@ bool MessagesManager::read_message_content(Dialog *d, Message *m, bool is_local_
LOG_CHECK(m != nullptr) << source;
CHECK(!m->message_id.is_scheduled());
bool is_mention_read = update_message_contains_unread_mention(d, m, false, "read_message_content");
bool is_content_read =
update_opened_message_content(m->content.get()) | ttl_on_open(d, m, Time::now(), is_local_read);
bool is_content_read = update_opened_message_content(m->content.get());
if (ttl_on_open(d, m, Time::now(), is_local_read)) {
is_content_read = true;
}
LOG(INFO) << "Read message content of " << m->message_id << " in " << d->dialog_id
<< ": is_mention_read = " << is_mention_read << ", is_content_read = " << is_content_read;
@ -13706,9 +13709,11 @@ std::pair<DialogId, unique_ptr<MessagesManager::Message>> MessagesManager::creat
bool noforwards = (flags & MESSAGE_FLAG_NOFORWARDS) != 0;
LOG_IF(ERROR, is_channel_message != (dialog_type == DialogType::Channel))
<< "is_channel_message is wrong for " << message_id << " received in the " << dialog_id;
LOG_IF(ERROR, is_channel_post && !is_broadcast_channel(dialog_id))
<< "is_channel_post is true for " << message_id << " received in the " << dialog_id;
<< "Receive wrong is_channel_message for " << message_id << " in " << dialog_id;
if (is_channel_post && !is_broadcast_channel(dialog_id)) {
LOG(ERROR) << "Receive is_channel_post for " << message_id << " in " << dialog_id;
is_channel_post = false;
}
UserId my_id = td_->contacts_manager_->get_my_id();
DialogId my_dialog_id = DialogId(my_id);
@ -13818,7 +13823,7 @@ std::pair<DialogId, unique_ptr<MessagesManager::Message>> MessagesManager::creat
LOG(ERROR) << "Wrong forward_count = " << forward_count << " received in " << message_id << " in " << dialog_id;
forward_count = 0;
}
MessageReplyInfo reply_info(std::move(message_info.reply_info), td_->auth_manager_->is_bot());
MessageReplyInfo reply_info(td_, std::move(message_info.reply_info), td_->auth_manager_->is_bot());
if (!top_thread_message_id.is_valid() && !is_broadcast_channel(dialog_id) &&
is_active_message_reply_info(dialog_id, reply_info) && !message_id.is_scheduled()) {
top_thread_message_id = message_id;
@ -14770,7 +14775,7 @@ void MessagesManager::on_get_dialogs(FolderId folder_id, vector<tl_object_ptr<te
DialogDate dialog_date = it->second;
CHECK(dialog_date.get_dialog_id() == dialog_id);
if (max_dialog_date < dialog_date) {
if (dialog_date.get_date() > 0 && max_dialog_date < dialog_date) {
max_dialog_date = dialog_date;
}
} else {
@ -16123,7 +16128,7 @@ void MessagesManager::load_folder_dialog_list(FolderId folder_id, int32 limit, b
}
return;
}
LOG(INFO) << "Load dialog list in " << folder_id << " with limit " << limit;
LOG(INFO) << "Load chat list in " << folder_id << " with limit " << limit;
multipromise.add_promise(PromiseCreator::lambda([actor_id = actor_id(this), folder_id](Result<Unit> result) {
send_closure_later(actor_id, &MessagesManager::on_load_folder_dialog_list, folder_id, std::move(result));
}));
@ -16255,6 +16260,13 @@ void MessagesManager::on_get_dialogs_from_database(FolderId folder_id, int32 lim
if (!have_more_dialogs_in_database) {
folder.last_loaded_database_dialog_date_ = MAX_DIALOG_DATE;
LOG(INFO) << "Set last loaded database dialog date to " << folder.last_loaded_database_dialog_date_;
if (folder.last_database_server_dialog_date_.get_date() == 0 &&
folder.last_database_server_dialog_date_ != MAX_DIALOG_DATE) {
// replace definitely wrong folder.last_database_server_dialog_date_ with max_dialog_date
LOG(ERROR) << "Fix last database server dialog date from " << folder.last_database_server_dialog_date_ << " to "
<< max_dialog_date;
folder.last_database_server_dialog_date_ = max_dialog_date;
}
folder.last_server_dialog_date_ = max(folder.last_server_dialog_date_, folder.last_database_server_dialog_date_);
LOG(INFO) << "Set last server dialog date to " << folder.last_server_dialog_date_;
update_last_dialog_date(folder_id);
@ -17499,7 +17511,7 @@ td_api::object_ptr<td_api::messageThreadInfo> MessagesManager::get_message_threa
auto message = get_message_object(d->dialog_id, m, "get_message_thread_info_object");
if (message != nullptr) {
if (message->interaction_info_ != nullptr && message->interaction_info_->reply_info_ != nullptr) {
reply_info = m->reply_info.get_message_reply_info_object(td_->contacts_manager_.get(), this);
reply_info = m->reply_info.get_message_reply_info_object(td_);
CHECK(reply_info != nullptr);
}
messages.push_back(std::move(message));
@ -20201,7 +20213,7 @@ void MessagesManager::open_dialog(Dialog *d) {
d->default_send_message_as_dialog_id = DialogId();
LOG(INFO) << "Set message sender in " << d->dialog_id << " to " << d->default_send_message_as_dialog_id;
on_dialog_updated(dialog_id, "open_dialog");
send_update_chat_default_message_sender_id(d);
send_update_chat_message_sender(d);
}
switch (dialog_id.get_type()) {
@ -20417,10 +20429,11 @@ td_api::object_ptr<td_api::videoChat> MessagesManager::get_video_chat_object(con
std::move(default_participant_alias));
}
td_api::object_ptr<td_api::MessageSender> MessagesManager::get_default_sender_id_object(const Dialog *d) const {
td_api::object_ptr<td_api::MessageSender> MessagesManager::get_default_message_sender_object(const Dialog *d) const {
auto as_dialog_id = d->default_send_message_as_dialog_id;
return as_dialog_id.is_valid() ? get_message_sender_object_const(td_, as_dialog_id, "get_default_sender_id_object")
: nullptr;
return as_dialog_id.is_valid()
? get_message_sender_object_const(td_, as_dialog_id, "get_default_message_sender_object")
: nullptr;
}
td_api::object_ptr<td_api::chat> MessagesManager::get_chat_object(const Dialog *d) const {
@ -20487,15 +20500,16 @@ td_api::object_ptr<td_api::chat> MessagesManager::get_chat_object(const Dialog *
get_chat_photo_info_object(td_->file_manager_.get(), get_dialog_photo(d->dialog_id)),
get_dialog_default_permissions(d->dialog_id).get_chat_permissions_object(),
get_message_object(d->dialog_id, get_message(d, d->last_message_id), "get_chat_object"),
get_chat_positions_object(d), get_default_sender_id_object(d), get_dialog_has_protected_content(d->dialog_id),
d->is_marked_as_unread, d->is_blocked, get_dialog_has_scheduled_messages(d), can_delete_for_self,
can_delete_for_all_users, can_report_dialog(d->dialog_id), d->notification_settings.silent_send_message,
get_chat_positions_object(d), get_default_message_sender_object(d),
get_dialog_has_protected_content(d->dialog_id), d->is_marked_as_unread, d->is_blocked,
get_dialog_has_scheduled_messages(d), can_delete_for_self, can_delete_for_all_users,
can_report_dialog(d->dialog_id), d->notification_settings.silent_send_message,
d->server_unread_count + d->local_unread_count, d->last_read_inbox_message_id.get(),
d->last_read_outbox_message_id.get(), d->unread_mention_count,
get_chat_notification_settings_object(&d->notification_settings),
d->message_ttl_setting.get_message_ttl_setting_object(), get_dialog_theme_name(d), get_chat_action_bar_object(d),
get_video_chat_object(d), get_chat_join_requests_info_object(d), d->reply_markup_message_id.get(),
std::move(draft_message), d->client_data);
get_chat_notification_settings_object(&d->notification_settings), d->message_ttl.get_message_ttl_object(),
get_dialog_theme_name(d), get_chat_action_bar_object(d), get_video_chat_object(d),
get_chat_join_requests_info_object(d), d->reply_markup_message_id.get(), std::move(draft_message),
d->client_data);
}
tl_object_ptr<td_api::chat> MessagesManager::get_chat_object(DialogId dialog_id) const {
@ -23620,14 +23634,15 @@ tl_object_ptr<td_api::MessageSchedulingState> MessagesManager::get_message_sched
}
td_api::object_ptr<td_api::message> MessagesManager::get_dialog_event_log_message_object(
DialogId dialog_id, tl_object_ptr<telegram_api::Message> &&message) {
DialogId dialog_id, tl_object_ptr<telegram_api::Message> &&message, DialogId &sender_dialog_id) {
auto dialog_message = create_message(parse_telegram_api_message(std::move(message), false, "dialog_event_log"),
dialog_id.get_type() == DialogType::Channel);
if (dialog_message.second == nullptr || dialog_message.first != dialog_id) {
LOG(ERROR) << "Failed to create event log message in " << dialog_id;
return nullptr;
}
return get_message_object(dialog_id, dialog_message.second.get(), "admin log", true);
sender_dialog_id = get_message_sender(dialog_message.second.get());
return get_message_object(dialog_id, dialog_message.second.get(), "get_dialog_event_log_message_object", true);
}
tl_object_ptr<td_api::message> MessagesManager::get_message_object(FullMessageId full_message_id, const char *source) {
@ -24198,8 +24213,14 @@ void MessagesManager::add_message_dependencies(Dependencies &dependencies, const
add_dialog_and_dependencies(dependencies, m->forward_info->sender_dialog_id);
add_dialog_and_dependencies(dependencies, m->forward_info->from_dialog_id);
}
for (const auto &replier_min_channel : m->reply_info.replier_min_channels) {
LOG(INFO) << "Add min " << replier_min_channel.first;
td_->contacts_manager_->add_min_channel(replier_min_channel.first, replier_min_channel.second);
}
for (auto recent_replier_dialog_id : m->reply_info.recent_replier_dialog_ids) {
add_message_sender_dependencies(dependencies, recent_replier_dialog_id);
// don't load the dialog itself
// it will be created in get_message_reply_info_object if needed
add_dialog_dependencies(dependencies, recent_replier_dialog_id);
}
add_message_content_dependencies(dependencies, m->content.get());
add_reply_markup_dependencies(dependencies, m->reply_markup.get());
@ -29682,22 +29703,22 @@ void MessagesManager::send_update_chat_video_chat(const Dialog *d) {
td_api::make_object<td_api::updateChatVideoChat>(d->dialog_id.get(), get_video_chat_object(d)));
}
void MessagesManager::send_update_chat_default_message_sender_id(const Dialog *d) {
void MessagesManager::send_update_chat_message_sender(const Dialog *d) {
CHECK(!td_->auth_manager_->is_bot());
CHECK(d != nullptr);
LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_default_message_sender_id";
send_closure(G()->td(), &Td::send_update,
td_api::make_object<td_api::updateChatDefaultMessageSenderId>(d->dialog_id.get(),
get_default_sender_id_object(d)));
LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_message_sender";
send_closure(
G()->td(), &Td::send_update,
td_api::make_object<td_api::updateChatMessageSender>(d->dialog_id.get(), get_default_message_sender_object(d)));
}
void MessagesManager::send_update_chat_message_ttl_setting(const Dialog *d) {
void MessagesManager::send_update_chat_message_ttl(const Dialog *d) {
CHECK(d != nullptr);
LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_message_ttl_setting";
on_dialog_updated(d->dialog_id, "send_update_chat_message_ttl_setting");
send_closure(G()->td(), &Td::send_update,
td_api::make_object<td_api::updateChatMessageTtlSetting>(
d->dialog_id.get(), d->message_ttl_setting.get_message_ttl_setting_object()));
LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_message_ttl";
on_dialog_updated(d->dialog_id, "send_update_chat_message_ttl");
send_closure(
G()->td(), &Td::send_update,
td_api::make_object<td_api::updateChatMessageTtl>(d->dialog_id.get(), d->message_ttl.get_message_ttl_object()));
}
void MessagesManager::send_update_chat_has_scheduled_messages(Dialog *d, bool from_deletion) {
@ -31098,7 +31119,7 @@ void MessagesManager::on_update_dialog_default_send_message_as_dialog_id(DialogI
LOG(INFO) << "Set message sender in " << dialog_id << " to " << default_send_as_dialog_id;
d->need_drop_default_send_message_as_dialog_id = false;
d->default_send_message_as_dialog_id = default_send_as_dialog_id;
send_update_chat_default_message_sender_id(d);
send_update_chat_message_sender(d);
} else {
LOG(INFO) << "Postpone removal of message sender in " << dialog_id;
d->need_drop_default_send_message_as_dialog_id = true;
@ -31111,21 +31132,21 @@ void MessagesManager::on_update_dialog_default_send_message_as_dialog_id(DialogI
}
}
void MessagesManager::on_update_dialog_message_ttl_setting(DialogId dialog_id, MessageTtlSetting message_ttl_setting) {
auto d = get_dialog_force(dialog_id, "on_update_dialog_message_ttl_setting");
void MessagesManager::on_update_dialog_message_ttl(DialogId dialog_id, MessageTtl message_ttl) {
auto d = get_dialog_force(dialog_id, "on_update_dialog_message_ttl");
if (d == nullptr) {
// nothing to do
return;
}
if (d->message_ttl_setting != message_ttl_setting) {
d->message_ttl_setting = message_ttl_setting;
d->is_message_ttl_setting_inited = true;
send_update_chat_message_ttl_setting(d);
if (d->message_ttl != message_ttl) {
d->message_ttl = message_ttl;
d->is_message_ttl_inited = true;
send_update_chat_message_ttl(d);
}
if (!d->is_message_ttl_setting_inited) {
d->is_message_ttl_setting_inited = true;
on_dialog_updated(dialog_id, "on_update_dialog_message_ttl_setting");
if (!d->is_message_ttl_inited) {
d->is_message_ttl_inited = true;
on_dialog_updated(dialog_id, "on_update_dialog_message_ttl");
}
}
@ -32273,12 +32294,12 @@ void MessagesManager::set_dialog_title(DialogId dialog_id, const string &title,
td_->create_handler<EditDialogTitleQuery>(std::move(promise))->send(dialog_id, new_title);
}
void MessagesManager::set_dialog_message_ttl_setting(DialogId dialog_id, int32 ttl, Promise<Unit> &&promise) {
void MessagesManager::set_dialog_message_ttl(DialogId dialog_id, int32 ttl, Promise<Unit> &&promise) {
if (ttl < 0) {
return promise.set_error(Status::Error(400, "Message auto-delete time can't be negative"));
}
Dialog *d = get_dialog_force(dialog_id, "set_dialog_message_ttl_setting");
Dialog *d = get_dialog_force(dialog_id, "set_dialog_message_ttl");
if (d == nullptr) {
return promise.set_error(Status::Error(400, "Chat not found"));
}
@ -32329,7 +32350,7 @@ void MessagesManager::set_dialog_message_ttl_setting(DialogId dialog_id, int32 t
send_update_new_message(d, m);
if (need_update_dialog_pos) {
send_update_chat_last_message(d, "set_dialog_message_ttl_setting");
send_update_chat_last_message(d, "set_dialog_message_ttl");
}
int64 random_id = begin_send_message(dialog_id, m);
@ -34859,7 +34880,13 @@ void MessagesManager::force_create_dialog(DialogId dialog_id, const char *source
}
if (!have_input_peer(dialog_id, AccessRights::Read)) {
if (!have_dialog_info(dialog_id)) {
LOG(ERROR) << "Have no info about " << dialog_id << " received from " << source << ", but forced to create it";
if (expect_no_access && dialog_id.get_type() == DialogType::Channel &&
td_->contacts_manager_->have_min_channel(dialog_id.get_channel_id())) {
LOG(INFO) << "Created " << dialog_id << " for min-channel from " << source;
} else {
LOG(ERROR) << "Have no info about " << dialog_id << " received from " << source
<< ", but forced to create it";
}
} else if (!expect_no_access) {
LOG(ERROR) << "Have no access to " << dialog_id << " received from " << source << ", but forced to create it";
}
@ -34948,9 +34975,8 @@ MessagesManager::Dialog *MessagesManager::add_new_dialog(unique_ptr<Dialog> &&d,
do_set_dialog_folder_id(
d.get(), td_->contacts_manager_->get_secret_chat_initial_folder_id(dialog_id.get_secret_chat_id()));
}
d->message_ttl_setting =
MessageTtlSetting(td_->contacts_manager_->get_secret_chat_ttl(dialog_id.get_secret_chat_id()));
d->is_message_ttl_setting_inited = true;
d->message_ttl = MessageTtl(td_->contacts_manager_->get_secret_chat_ttl(dialog_id.get_secret_chat_id()));
d->is_message_ttl_inited = true;
d->has_bots = td_->contacts_manager_->is_user_bot(
td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()));
d->is_has_bots_inited = true;
@ -35088,10 +35114,10 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr<Message> &&last_datab
order != DEFAULT_ORDER) {
// asynchronously get dialog folder identifier from the server
get_dialog_info_full(dialog_id, Auto(), "fix_new_dialog init folder_id");
} else if (!d->is_message_ttl_setting_inited && !td_->auth_manager_->is_bot() &&
} else if (!d->is_message_ttl_inited && !td_->auth_manager_->is_bot() &&
have_input_peer(dialog_id, AccessRights::Write)) {
// asynchronously get dialog message TTL setting from the server
get_dialog_info_full(dialog_id, Auto(), "fix_new_dialog init message_ttl_setting");
// asynchronously get dialog message TTL from the server
get_dialog_info_full(dialog_id, Auto(), "fix_new_dialog init message_ttl");
}
if ((!d->know_action_bar || d->need_repair_action_bar) && !td_->auth_manager_->is_bot() &&
dialog_type != DialogType::SecretChat && dialog_id != get_my_dialog_id() &&
@ -35201,7 +35227,7 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr<Message> &&last_datab
LOG(INFO) << "Set postponed message sender in " << pending_dialog_id << " to " << dialog_id;
pending_d->need_drop_default_send_message_as_dialog_id = pending_dialog_id.second;
pending_d->default_send_message_as_dialog_id = dialog_id;
send_update_chat_default_message_sender_id(pending_d);
send_update_chat_message_sender(pending_d);
}
}
}
@ -35316,7 +35342,7 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr<Message> &&last_datab
LOG(INFO) << "Set message sender in " << dialog_id << " to " << default_send_message_as_dialog_id;
d->need_drop_default_send_message_as_dialog_id = need_drop_default_send_message_as_dialog_id;
d->default_send_message_as_dialog_id = default_send_message_as_dialog_id;
send_update_chat_default_message_sender_id(d);
send_update_chat_message_sender(d);
}
}
@ -37290,7 +37316,8 @@ void MessagesManager::reget_message_from_server_if_needed(DialogId dialog_id, co
return;
}
if (need_reget_message_content(m->content.get()) || (m->legacy_layer != 0 && m->legacy_layer < MTPROTO_LAYER)) {
if (need_reget_message_content(m->content.get()) || (m->legacy_layer != 0 && m->legacy_layer < MTPROTO_LAYER) ||
m->reply_info.need_reget(td_)) {
FullMessageId full_message_id{dialog_id, m->message_id};
LOG(INFO) << "Reget from server " << full_message_id;
get_message_from_server(full_message_id, Auto(), "reget_message_from_server_if_needed");

View File

@ -35,7 +35,7 @@
#include "td/telegram/MessagesDb.h"
#include "td/telegram/MessageSearchFilter.h"
#include "td/telegram/MessageThreadInfo.h"
#include "td/telegram/MessageTtlSetting.h"
#include "td/telegram/MessageTtl.h"
#include "td/telegram/net/DcId.h"
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/Notification.h"
@ -312,7 +312,7 @@ class MessagesManager final : public Actor {
void on_update_dialog_default_send_message_as_dialog_id(DialogId dialog_id, DialogId default_send_as_dialog_id,
bool force);
void on_update_dialog_message_ttl_setting(DialogId dialog_id, MessageTtlSetting message_ttl_setting);
void on_update_dialog_message_ttl(DialogId dialog_id, MessageTtl message_ttl);
void on_update_dialog_filters();
@ -430,7 +430,7 @@ class MessagesManager final : public Actor {
Result<vector<MessageId>> resend_messages(DialogId dialog_id, vector<MessageId> message_ids) TD_WARN_UNUSED_RESULT;
void set_dialog_message_ttl_setting(DialogId dialog_id, int32 ttl, Promise<Unit> &&promise);
void set_dialog_message_ttl(DialogId dialog_id, int32 ttl, Promise<Unit> &&promise);
Status send_screenshot_taken_notification_message(DialogId dialog_id);
@ -774,7 +774,7 @@ class MessagesManager final : public Actor {
tl_object_ptr<td_api::message> get_dialog_message_by_date_object(int64 random_id);
td_api::object_ptr<td_api::message> get_dialog_event_log_message_object(
DialogId dialog_id, tl_object_ptr<telegram_api::Message> &&message);
DialogId dialog_id, tl_object_ptr<telegram_api::Message> &&message, DialogId &sender_dialog_id);
tl_object_ptr<td_api::message> get_message_object(FullMessageId full_message_id, const char *source);
@ -1207,7 +1207,7 @@ class MessagesManager final : public Actor {
MessageId last_pinned_message_id;
MessageId reply_markup_message_id;
DialogNotificationSettings notification_settings;
MessageTtlSetting message_ttl_setting;
MessageTtl message_ttl;
unique_ptr<DraftMessage> draft_message;
unique_ptr<DialogActionBar> action_bar;
LogEventIdWithGeneration save_draft_message_log_event_id;
@ -1289,7 +1289,7 @@ class MessagesManager final : public Actor {
bool had_last_yet_unsent_message = false; // whether the dialog was stored to database without last message
bool has_active_group_call = false;
bool is_group_call_empty = false;
bool is_message_ttl_setting_inited = false;
bool is_message_ttl_inited = false;
bool has_expected_active_group_call_id = false;
bool has_bots = false;
bool is_has_bots_inited = false;
@ -2400,9 +2400,9 @@ class MessagesManager final : public Actor {
void send_update_chat_video_chat(const Dialog *d);
void send_update_chat_default_message_sender_id(const Dialog *d);
void send_update_chat_message_sender(const Dialog *d);
void send_update_chat_message_ttl_setting(const Dialog *d);
void send_update_chat_message_ttl(const Dialog *d);
void send_update_chat_has_scheduled_messages(Dialog *d, bool from_deletion);
@ -2601,7 +2601,7 @@ class MessagesManager final : public Actor {
td_api::object_ptr<td_api::videoChat> get_video_chat_object(const Dialog *d) const;
td_api::object_ptr<td_api::MessageSender> get_default_sender_id_object(const Dialog *d) const;
td_api::object_ptr<td_api::MessageSender> get_default_message_sender_object(const Dialog *d) const;
td_api::object_ptr<td_api::chat> get_chat_object(const Dialog *d) const;
@ -3111,9 +3111,9 @@ class MessagesManager final : public Actor {
return !LOG_IS_STRIPPED(ERROR) && false;
}
static void dump_debug_message_op(const Dialog *d, int priority = 0);
void add_message_dependencies(Dependencies &dependencies, const Message *m);
static void add_message_dependencies(Dependencies &dependencies, const Message *m);
static void dump_debug_message_op(const Dialog *d, int priority = 0);
static void save_send_message_log_event(DialogId dialog_id, const Message *m);

21
td/telegram/MinChannel.h Normal file
View File

@ -0,0 +1,21 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once
#include "td/telegram/Photo.h"
#include "td/utils/common.h"
namespace td {
struct MinChannel {
string title_;
DialogPhoto photo_;
bool is_megagroup_ = false;
};
} // namespace td

View File

@ -0,0 +1,51 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once
#include "td/telegram/MinChannel.h"
#include "td/telegram/Photo.hpp"
#include "td/utils/common.h"
#include "td/utils/tl_helpers.h"
namespace td {
template <class StorerT>
void store(const MinChannel &min_channel, StorerT &storer) {
bool has_title = !min_channel.title_.empty();
bool has_photo = min_channel.photo_.small_file_id.is_valid();
BEGIN_STORE_FLAGS();
STORE_FLAG(has_title);
STORE_FLAG(has_photo);
STORE_FLAG(min_channel.is_megagroup_);
END_STORE_FLAGS();
if (has_title) {
store(min_channel.title_, storer);
}
if (has_photo) {
store(min_channel.photo_, storer);
}
}
template <class ParserT>
void parse(MinChannel &min_channel, ParserT &parser) {
bool has_title;
bool has_photo;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(has_title);
PARSE_FLAG(has_photo);
PARSE_FLAG(min_channel.is_megagroup_);
END_PARSE_FLAGS();
if (has_title) {
parse(min_channel.title_, parser);
}
if (has_photo) {
parse(min_channel.photo_, parser);
}
}
} // namespace td

View File

@ -140,7 +140,7 @@ class SecretChatActor final : public NetQueryCallback {
static constexpr int32 MAX_RESEND_COUNT = 1000;
// We have git state that should be synchronized with the database.
// It is splitted into several parts because:
// It is split into several parts because:
// 1. Some parts are BIG (auth_key, for example) and are rarely updated.
// 2. Other are frequently updated, so probably should be as small as possible.
// 3. Some parts must be updated atomically.
@ -494,7 +494,8 @@ class SecretChatActor final : public NetQueryCallback {
template <class StateT>
class Change {
public:
Change() = default;
Change() : message_id() {
}
explicit operator bool() const {
return !data.empty();
}
@ -520,7 +521,7 @@ class SecretChatActor final : public NetQueryCallback {
return sb;
}
int32 message_id = 0;
int32 message_id;
private:
std::string data;

View File

@ -21,6 +21,7 @@
#include "td/utils/algorithm.h"
#include "td/utils/buffer.h"
#include "td/utils/logging.h"
#include "td/utils/Random.h"
#include "td/utils/SliceBuilder.h"
#include "td/utils/Status.h"
@ -114,7 +115,7 @@ struct SponsoredMessageManager::SponsoredMessage {
};
struct SponsoredMessageManager::DialogSponsoredMessages {
vector<Promise<td_api::object_ptr<td_api::sponsoredMessages>>> promises;
vector<Promise<td_api::object_ptr<td_api::sponsoredMessage>>> promises;
vector<SponsoredMessage> messages;
std::unordered_map<int32, string> message_random_ids;
};
@ -184,27 +185,28 @@ td_api::object_ptr<td_api::sponsoredMessage> SponsoredMessageManager::get_sponso
get_message_content_object(sponsored_message.content.get(), td_, dialog_id, 0, false, true, -1));
}
td_api::object_ptr<td_api::sponsoredMessages> SponsoredMessageManager::get_sponsored_messages_object(
td_api::object_ptr<td_api::sponsoredMessage> SponsoredMessageManager::get_sponsored_message_object(
DialogId dialog_id, const DialogSponsoredMessages &sponsored_messages) const {
return td_api::make_object<td_api::sponsoredMessages>(
transform(sponsored_messages.messages, [this, dialog_id](const SponsoredMessage &sponsored_message) {
return get_sponsored_message_object(dialog_id, sponsored_message);
}));
if (sponsored_messages.messages.empty()) {
return nullptr;
}
auto pos = Random::fast(0, static_cast<int>(sponsored_messages.messages.size()) - 1);
return get_sponsored_message_object(dialog_id, sponsored_messages.messages[pos]);
}
void SponsoredMessageManager::get_dialog_sponsored_messages(
DialogId dialog_id, Promise<td_api::object_ptr<td_api::sponsoredMessages>> &&promise) {
if (!td_->messages_manager_->have_dialog_force(dialog_id, "get_sponsored_messages")) {
void SponsoredMessageManager::get_dialog_sponsored_message(
DialogId dialog_id, Promise<td_api::object_ptr<td_api::sponsoredMessage>> &&promise) {
if (!td_->messages_manager_->have_dialog_force(dialog_id, "get_dialog_sponsored_message")) {
return promise.set_error(Status::Error(400, "Chat not found"));
}
if (dialog_id.get_type() != DialogType::Channel ||
td_->contacts_manager_->get_channel_type(dialog_id.get_channel_id()) != ContactsManager::ChannelType::Broadcast) {
return promise.set_value(td_api::make_object<td_api::sponsoredMessages>());
return promise.set_value(nullptr);
}
auto &messages = dialog_sponsored_messages_[dialog_id];
if (messages != nullptr && messages->promises.empty()) {
return promise.set_value(get_sponsored_messages_object(dialog_id, *messages));
return promise.set_value(get_sponsored_message_object(dialog_id, *messages));
}
if (messages == nullptr) {
@ -280,7 +282,7 @@ void SponsoredMessageManager::on_get_dialog_sponsored_messages(
}
for (auto &promise : promises) {
promise.set_value(get_sponsored_messages_object(dialog_id, *messages));
promise.set_value(get_sponsored_message_object(dialog_id, *messages));
}
delete_cached_sponsored_messages_timeout_.set_timeout_in(dialog_id.get(), 300.0);
}

View File

@ -32,8 +32,8 @@ class SponsoredMessageManager final : public Actor {
SponsoredMessageManager &operator=(SponsoredMessageManager &&) = delete;
~SponsoredMessageManager() final;
void get_dialog_sponsored_messages(DialogId dialog_id,
Promise<td_api::object_ptr<td_api::sponsoredMessages>> &&promise);
void get_dialog_sponsored_message(DialogId dialog_id,
Promise<td_api::object_ptr<td_api::sponsoredMessage>> &&promise);
void view_sponsored_message(DialogId dialog_id, int32 sponsored_message_id, Promise<Unit> &&promise);
@ -51,7 +51,7 @@ class SponsoredMessageManager final : public Actor {
td_api::object_ptr<td_api::sponsoredMessage> get_sponsored_message_object(
DialogId dialog_id, const SponsoredMessage &sponsored_message) const;
td_api::object_ptr<td_api::sponsoredMessages> get_sponsored_messages_object(
td_api::object_ptr<td_api::sponsoredMessage> get_sponsored_message_object(
DialogId dialog_id, const DialogSponsoredMessages &sponsored_messages) const;
void on_get_dialog_sponsored_messages(

View File

@ -2004,23 +2004,28 @@ std::pair<FileId, int> StickersManager::get_animated_emoji_sticker(const Sticker
return {};
}
auto emoji_without_selectors = remove_emoji_selectors(emoji);
// 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};
for (auto &sticker_emoji : emoji_it->second) {
if (remove_emoji_selectors(sticker_emoji) == emoji_without_selectors) {
return {sticker_id, 0};
}
}
}
// trying to find match without Fitzpatrick modifiers
int modifier_id = get_fitzpatrick_modifier(emoji);
int modifier_id = get_fitzpatrick_modifier(emoji_without_selectors);
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};
for (auto &sticker_emoji : emoji_it->second) {
if (remove_emoji_selectors(sticker_emoji) == Slice(emoji_without_selectors).remove_suffix(4)) {
return {sticker_id, modifier_id};
}
}
}
}

View File

@ -35,7 +35,7 @@ SuggestedAction::SuggestedAction(Slice action_str) {
} else if (action_str == Slice("VALIDATE_PHONE_NUMBER")) {
init(Type::CheckPhoneNumber);
} else if (action_str == Slice("NEWCOMER_TICKS")) {
init(Type::SeeTicksHint);
init(Type::ViewChecksHint);
}
}
@ -61,8 +61,8 @@ SuggestedAction::SuggestedAction(const td_api::object_ptr<td_api::SuggestedActio
case td_api::suggestedActionCheckPhoneNumber::ID:
init(Type::CheckPhoneNumber);
break;
case td_api::suggestedActionSeeTicksHint::ID:
init(Type::SeeTicksHint);
case td_api::suggestedActionViewChecksHint::ID:
init(Type::ViewChecksHint);
break;
case td_api::suggestedActionConvertToBroadcastGroup::ID: {
auto action = static_cast<const td_api::suggestedActionConvertToBroadcastGroup *>(suggested_action.get());
@ -92,7 +92,7 @@ string SuggestedAction::get_suggested_action_str() const {
return "VALIDATE_PASSWORD";
case Type::CheckPhoneNumber:
return "VALIDATE_PHONE_NUMBER";
case Type::SeeTicksHint:
case Type::ViewChecksHint:
return "NEWCOMER_TICKS";
case Type::ConvertToGigagroup:
return "CONVERT_GIGAGROUP";
@ -111,8 +111,8 @@ td_api::object_ptr<td_api::SuggestedAction> SuggestedAction::get_suggested_actio
return td_api::make_object<td_api::suggestedActionCheckPassword>();
case Type::CheckPhoneNumber:
return td_api::make_object<td_api::suggestedActionCheckPhoneNumber>();
case Type::SeeTicksHint:
return td_api::make_object<td_api::suggestedActionSeeTicksHint>();
case Type::ViewChecksHint:
return td_api::make_object<td_api::suggestedActionViewChecksHint>();
case Type::ConvertToGigagroup:
return td_api::make_object<td_api::suggestedActionConvertToBroadcastGroup>(dialog_id_.get_channel_id().get());
case Type::SetPassword:
@ -171,7 +171,7 @@ void dismiss_suggested_action(SuggestedAction action, Promise<Unit> &&promise) {
case SuggestedAction::Type::EnableArchiveAndMuteNewChats:
case SuggestedAction::Type::CheckPassword:
case SuggestedAction::Type::CheckPhoneNumber:
case SuggestedAction::Type::SeeTicksHint:
case SuggestedAction::Type::ViewChecksHint:
return send_closure_later(G()->config_manager(), &ConfigManager::dismiss_suggested_action, std::move(action),
std::move(promise));
case SuggestedAction::Type::ConvertToGigagroup:

View File

@ -21,7 +21,7 @@ struct SuggestedAction {
Empty,
EnableArchiveAndMuteNewChats,
CheckPhoneNumber,
SeeTicksHint,
ViewChecksHint,
ConvertToGigagroup,
CheckPassword,
SetPassword

View File

@ -26,7 +26,6 @@
#include "td/telegram/CountryInfoManager.h"
#include "td/telegram/DeviceTokenManager.h"
#include "td/telegram/DialogAction.h"
#include "td/telegram/DialogAdministrator.h"
#include "td/telegram/DialogEventLog.h"
#include "td/telegram/DialogFilter.h"
#include "td/telegram/DialogFilterId.h"
@ -1803,7 +1802,7 @@ class JoinChatByInviteLinkRequest final : public RequestActor<DialogId> {
void do_send_result() final {
CHECK(dialog_id_.is_valid());
td_->messages_manager_->force_create_dialog(dialog_id_, "join chat by invite link");
td_->messages_manager_->force_create_dialog(dialog_id_, "join chat via an invite link");
send_result(td_->messages_manager_->get_chat_object(dialog_id_));
}
@ -4732,10 +4731,10 @@ void Td::on_request(uint64 id, const td_api::getMessages &request) {
CREATE_REQUEST(GetMessagesRequest, request.chat_id_, request.message_ids_);
}
void Td::on_request(uint64 id, const td_api::getChatSponsoredMessages &request) {
void Td::on_request(uint64 id, const td_api::getChatSponsoredMessage &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
sponsored_message_manager_->get_dialog_sponsored_messages(DialogId(request.chat_id_), std::move(promise));
sponsored_message_manager_->get_dialog_sponsored_message(DialogId(request.chat_id_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::viewSponsoredMessage &request) {
@ -5339,11 +5338,11 @@ void Td::on_request(uint64 id, const td_api::getChatAvailableMessageSenders &req
messages_manager_->get_dialog_send_message_as_dialog_ids(DialogId(request.chat_id_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::setChatDefaultMessageSender &request) {
void Td::on_request(uint64 id, const td_api::setChatMessageSender &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
TRY_RESULT_PROMISE(promise, message_sender_dialog_id,
get_message_sender_dialog_id(this, request.default_message_sender_id_, true, false));
get_message_sender_dialog_id(this, request.message_sender_id_, true, false));
messages_manager_->set_dialog_default_send_message_as_dialog_id(DialogId(request.chat_id_), message_sender_dialog_id,
std::move(promise));
}
@ -5898,7 +5897,7 @@ void Td::on_request(uint64 id, const td_api::leaveGroupCall &request) {
group_call_manager_->leave_group_call(GroupCallId(request.group_call_id_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::discardGroupCall &request) {
void Td::on_request(uint64 id, const td_api::endGroupCall &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
group_call_manager_->discard_group_call(GroupCallId(request.group_call_id_), std::move(promise));
@ -5999,9 +5998,9 @@ void Td::on_request(uint64 id, const td_api::setChatPhoto &request) {
messages_manager_->set_dialog_photo(DialogId(request.chat_id_), request.photo_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::setChatMessageTtlSetting &request) {
void Td::on_request(uint64 id, const td_api::setChatMessageTtl &request) {
CREATE_OK_REQUEST_PROMISE();
messages_manager_->set_dialog_message_ttl_setting(DialogId(request.chat_id_), request.ttl_, std::move(promise));
messages_manager_->set_dialog_message_ttl(DialogId(request.chat_id_), request.ttl_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::setChatPermissions &request) {
@ -6224,7 +6223,7 @@ 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_), std::move(request.name_),
request.expire_date_, request.member_limit_,
request.expiration_date_, request.member_limit_,
request.creates_join_request_, false, std::move(promise));
}
@ -6233,8 +6232,8 @@ void Td::on_request(uint64 id, td_api::editChatInviteLink &request) {
CLEAN_INPUT_STRING(request.invite_link_);
CREATE_REQUEST_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));
request.expiration_date_, request.member_limit_,
request.creates_join_request_, std::move(promise));
}
void Td::on_request(uint64 id, td_api::getChatInviteLink &request) {

View File

@ -105,7 +105,7 @@ class Td final : public Actor {
Td &operator=(Td &&) = delete;
~Td() final;
static constexpr const char *TDLIB_VERSION = "1.7.10";
static constexpr const char *TDLIB_VERSION = "1.7.11";
struct Options {
std::shared_ptr<NetQueryStats> net_query_stats;
@ -534,7 +534,7 @@ class Td final : public Actor {
void on_request(uint64 id, const td_api::getMessages &request);
void on_request(uint64 id, const td_api::getChatSponsoredMessages &request);
void on_request(uint64 id, const td_api::getChatSponsoredMessage &request);
void on_request(uint64 id, const td_api::viewSponsoredMessage &request);
@ -672,7 +672,7 @@ class Td final : public Actor {
void on_request(uint64 id, const td_api::getChatAvailableMessageSenders &request);
void on_request(uint64 id, const td_api::setChatDefaultMessageSender &request);
void on_request(uint64 id, const td_api::setChatMessageSender &request);
void on_request(uint64 id, td_api::sendMessage &request);
@ -804,7 +804,7 @@ class Td final : public Actor {
void on_request(uint64 id, const td_api::leaveGroupCall &request);
void on_request(uint64 id, const td_api::discardGroupCall &request);
void on_request(uint64 id, const td_api::endGroupCall &request);
void on_request(uint64 id, td_api::getGroupCallStreamSegment &request);
@ -830,7 +830,7 @@ class Td final : public Actor {
void on_request(uint64 id, const td_api::setChatPhoto &request);
void on_request(uint64 id, const td_api::setChatMessageTtlSetting &request);
void on_request(uint64 id, const td_api::setChatMessageTtl &request);
void on_request(uint64 id, const td_api::setChatPermissions &request);

View File

@ -27,7 +27,7 @@
#include "td/telegram/Location.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/MessageTtlSetting.h"
#include "td/telegram/MessageTtl.h"
#include "td/telegram/net/DcOptions.h"
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/NotificationManager.h"
@ -2673,11 +2673,11 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updatePeerSettings> u
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updatePeerHistoryTTL> update, Promise<Unit> &&promise) {
MessageTtlSetting message_ttl_setting;
MessageTtl message_ttl;
if ((update->flags_ & telegram_api::updatePeerHistoryTTL::TTL_PERIOD_MASK) != 0) {
message_ttl_setting = MessageTtlSetting(update->ttl_period_);
message_ttl = MessageTtl(update->ttl_period_);
}
td_->messages_manager_->on_update_dialog_message_ttl_setting(DialogId(update->peer_), message_ttl_setting);
td_->messages_manager_->on_update_dialog_message_ttl(DialogId(update->peer_), message_ttl);
promise.set_value(Unit());
}

View File

@ -54,7 +54,6 @@
#include <algorithm>
#include <atomic>
#include <clocale>
#include <cstdio>
#include <cstdlib>
#include <ctime>
@ -1394,8 +1393,8 @@ class CliClient final : public Actor {
if (action == "number") {
return td_api::make_object<td_api::suggestedActionCheckPhoneNumber>();
}
if (action == "ticks") {
return td_api::make_object<td_api::suggestedActionSeeTicksHint>();
if (action == "checks") {
return td_api::make_object<td_api::suggestedActionViewChecksHint>();
}
if (begins_with(action, "giga")) {
return td_api::make_object<td_api::suggestedActionConvertToBroadcastGroup>(as_supergroup_id(action.substr(4)));
@ -2674,7 +2673,7 @@ class CliClient final : public Actor {
get_args(args, chat_id, message_ids);
send_request(td_api::make_object<td_api::getMessages>(as_chat_id(chat_id), as_message_ids(message_ids)));
} else if (op == "gsm") {
send_request(td_api::make_object<td_api::getChatSponsoredMessages>(as_chat_id(args)));
send_request(td_api::make_object<td_api::getChatSponsoredMessage>(as_chat_id(args)));
} else if (op == "vsm") {
string chat_id;
string sponsored_message_id;
@ -2988,30 +2987,30 @@ class CliClient final : public Actor {
td_api::make_object<td_api::loadGroupCallParticipants>(as_group_call_id(group_call_id), as_limit(limit)));
} else if (op == "lgc") {
send_request(td_api::make_object<td_api::leaveGroupCall>(as_group_call_id(args)));
} else if (op == "dgc") {
send_request(td_api::make_object<td_api::discardGroupCall>(as_group_call_id(args)));
} else if (op == "egc") {
send_request(td_api::make_object<td_api::endGroupCall>(as_group_call_id(args)));
} else if (op == "rpcil") {
const string &chat_id = args;
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 expiration_date;
int32 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,
get_args(args, chat_id, name, expiration_date, member_limit, creates_join_request);
send_request(td_api::make_object<td_api::createChatInviteLink>(as_chat_id(chat_id), name, expiration_date,
member_limit, creates_join_request));
} else if (op == "ecil") {
string chat_id;
string invite_link;
string name;
int32 expire_date;
int32 expiration_date;
int32 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));
get_args(args, chat_id, invite_link, name, expiration_date, member_limit, creates_join_request);
send_request(td_api::make_object<td_api::editChatInviteLink>(
as_chat_id(chat_id), invite_link, name, expiration_date, member_limit, creates_join_request));
} else if (op == "rcil") {
string chat_id;
string invite_link;
@ -3264,12 +3263,12 @@ class CliClient final : public Actor {
message_thread_id_ = std::move(args);
} else if (op == "gcams") {
send_request(td_api::make_object<td_api::getChatAvailableMessageSenders>(as_chat_id(args)));
} else if (op == "scdms") {
} else if (op == "scmsr") {
string chat_id;
string sender_id;
get_args(args, chat_id, sender_id);
send_request(
td_api::make_object<td_api::setChatDefaultMessageSender>(as_chat_id(chat_id), as_message_sender(sender_id)));
td_api::make_object<td_api::setChatMessageSender>(as_chat_id(chat_id), as_message_sender(sender_id)));
} else if (op == "sm" || op == "sms" || op == "smr" || op == "smf") {
string chat_id;
string reply_to_message_id;
@ -3908,11 +3907,11 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::setChatPhoto>(
as_chat_id(chat_id), td_api::make_object<td_api::inputChatPhotoAnimation>(as_input_file(animation),
to_double(main_frame_timestamp))));
} else if (op == "scmts") {
} else if (op == "scmt") {
string chat_id;
int32 ttl;
get_args(args, chat_id, ttl);
send_request(td_api::make_object<td_api::setChatMessageTtlSetting>(as_chat_id(chat_id), ttl));
send_request(td_api::make_object<td_api::setChatMessageTtl>(as_chat_id(chat_id), ttl));
} else if (op == "scperm") {
string chat_id;
string permissions;
@ -4672,8 +4671,7 @@ void main(int argc, char **argv) {
ClientManager::set_log_message_callback(0, on_log_message);
init_openssl_threads();
const char *locale_name = (std::setlocale(LC_ALL, "fr-FR") == nullptr ? "C" : "fr-FR");
std::locale new_locale(locale_name);
std::locale new_locale("C");
std::locale::global(new_locale);
SCOPE_EXIT {
std::locale::global(std::locale::classic());

View File

@ -18,87 +18,6 @@
* Fields of Bool type are stored as Boolean, fields of int32, int53, and double types are stored as Number, fields of
* int64 and string types are stored as String, fields of bytes type are base64 encoded and then stored as String,
* fields of array type are stored as Array.
* The main TDLib interface is asynchronous. To match requests with a corresponding response a field "@extra" can
* be added to the request object. The corresponding response will have an "@extra" field with exactly the same value.
*
* A TDLib client instance can be created through td_json_client_create.
* Requests then can be sent using td_json_client_send from any thread.
* New updates and request responses can be received through td_json_client_receive from any thread. This function
* must not be called simultaneously from two different threads. Also note that all updates and request responses
* must be applied in the order they were received to ensure consistency.
* Given this information, it's advisable to call this function from a dedicated thread.
* Some service TDLib requests can be executed synchronously from any thread by using td_json_client_execute.
* The TDLib client instance can be destroyed via td_json_client_destroy.
*
* General pattern of usage:
* \code
* void *client = td_json_client_create();
* // somehow share the client with other threads, which will be able to send requests via td_json_client_send
*
* const double WAIT_TIMEOUT = 10.0; // seconds
* int is_closed = 0; // should be set to 1, when updateAuthorizationState with authorizationStateClosed is received
* while (!is_closed) {
* const char *result = td_json_client_receive(client, WAIT_TIMEOUT);
* if (result) {
* // parse the result as JSON object and process it as an incoming update or an answer to a previously sent request
* }
* }
* td_json_client_destroy(client);
* \endcode
*/
#include "td/telegram/tdjson_export.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Creates a new instance of TDLib.
* \return Pointer to the created instance of TDLib.
*/
TDJSON_EXPORT void *td_json_client_create();
/**
* Sends request to the TDLib client. May be called from any thread.
* \param[in] client The client.
* \param[in] request JSON-serialized null-terminated request to TDLib.
*/
TDJSON_EXPORT void td_json_client_send(void *client, const char *request);
/**
* Receives incoming updates and request responses from the TDLib client. May be called from any thread, but
* must not be called simultaneously from two different threads.
* Returned pointer will be deallocated by TDLib during next call to td_json_client_receive or td_json_client_execute
* in the same thread, so it can't be used after that.
* \param[in] client The client.
* \param[in] timeout The maximum number of seconds allowed for this function to wait for new data.
* \return JSON-serialized null-terminated incoming update or request response. May be NULL if the timeout expires.
*/
TDJSON_EXPORT const char *td_json_client_receive(void *client, double timeout);
/**
* Synchronously executes TDLib request. May be called from any thread.
* Only a few requests can be executed synchronously.
* Returned pointer will be deallocated by TDLib during next call to td_json_client_receive or td_json_client_execute
* in the same thread, so it can't be used after that.
* \param[in] client The client. Currently ignored for all requests, so NULL can be passed.
* \param[in] request JSON-serialized null-terminated request to TDLib.
* \return JSON-serialized null-terminated request response.
*/
TDJSON_EXPORT const char *td_json_client_execute(void *client, const char *request);
/**
* Destroys the TDLib client instance. After this is called the client instance must not be used anymore.
* \param[in] client The client.
*/
TDJSON_EXPORT void td_json_client_destroy(void *client);
/**
* \file
* Alternatively, you can use new TDLib JSON interface, which will replace the current JSON interface in TDLib 2.0.0.
*
* Objects and functions serialization to JSON is the same for both JSON interfaces.
*
* The main TDLib interface is asynchronous. To match requests with a corresponding response, the field "@extra" can
* be added to the request object. The corresponding response will have an "@extra" field with exactly the same value.
@ -129,6 +48,12 @@ TDJSON_EXPORT void td_json_client_destroy(void *client);
* \endcode
*/
#include "td/telegram/tdjson_export.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Returns an opaque identifier of a new TDLib instance.
* The TDLib instance will not send updates until the first request is sent to it.
@ -181,6 +106,82 @@ typedef void (*td_log_message_callback_ptr)(int verbosity_level, const char *mes
*/
TDJSON_EXPORT void td_set_log_message_callback(int max_verbosity_level, td_log_message_callback_ptr callback);
/**
* \file
* Alternatively, you can use old TDLib JSON interface, which will be removed in TDLib 2.0.0.
*
* Objects and functions serialization to JSON is the same for both JSON interfaces.
*
* The main TDLib interface is asynchronous. To match requests with a corresponding response a field "@extra" can
* be added to the request object. The corresponding response will have an "@extra" field with exactly the same value.
*
* A TDLib client instance can be created through td_json_client_create.
* Requests then can be sent using td_json_client_send from any thread.
* New updates and request responses can be received through td_json_client_receive from any thread. This function
* must not be called simultaneously from two different threads. Also note that all updates and request responses
* must be applied in the order they were received to ensure consistency.
* Given this information, it's advisable to call this function from a dedicated thread.
* Some service TDLib requests can be executed synchronously from any thread by using td_json_client_execute.
* The TDLib client instance can be destroyed via td_json_client_destroy.
*
* General pattern of usage:
* \code
* void *client = td_json_client_create();
* // somehow share the client with other threads, which will be able to send requests via td_json_client_send
*
* const double WAIT_TIMEOUT = 10.0; // seconds
* int is_closed = 0; // should be set to 1, when updateAuthorizationState with authorizationStateClosed is received
* while (!is_closed) {
* const char *result = td_json_client_receive(client, WAIT_TIMEOUT);
* if (result) {
* // parse the result as JSON object and process it as an incoming update or an answer to a previously sent request
* }
* }
* td_json_client_destroy(client);
* \endcode
*/
/**
* Creates a new instance of TDLib.
* \return Pointer to the created instance of TDLib.
*/
TDJSON_EXPORT void *td_json_client_create();
/**
* Sends request to the TDLib client. May be called from any thread.
* \param[in] client The client.
* \param[in] request JSON-serialized null-terminated request to TDLib.
*/
TDJSON_EXPORT void td_json_client_send(void *client, const char *request);
/**
* Receives incoming updates and request responses from the TDLib client. May be called from any thread, but
* must not be called simultaneously from two different threads.
* Returned pointer will be deallocated by TDLib during next call to td_json_client_receive or td_json_client_execute
* in the same thread, so it can't be used after that.
* \param[in] client The client.
* \param[in] timeout The maximum number of seconds allowed for this function to wait for new data.
* \return JSON-serialized null-terminated incoming update or request response. May be NULL if the timeout expires.
*/
TDJSON_EXPORT const char *td_json_client_receive(void *client, double timeout);
/**
* Synchronously executes TDLib request. May be called from any thread.
* Only a few requests can be executed synchronously.
* Returned pointer will be deallocated by TDLib during next call to td_json_client_receive or td_json_client_execute
* in the same thread, so it can't be used after that.
* \param[in] client The client. Currently ignored for all requests, so NULL can be passed.
* \param[in] request JSON-serialized null-terminated request to TDLib.
* \return JSON-serialized null-terminated request response.
*/
TDJSON_EXPORT const char *td_json_client_execute(void *client, const char *request);
/**
* Destroys the TDLib client instance. After this is called the client instance must not be used anymore.
* \param[in] client The client.
*/
TDJSON_EXPORT void td_json_client_destroy(void *client);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -184,23 +184,33 @@ class SafePromise;
template <class T = Unit>
class Promise;
constexpr std::false_type is_promise_interface(...);
constexpr inline std::false_type is_promise_interface(...) {
return {};
}
template <class T>
constexpr std::true_type is_promise_interface(const PromiseInterface<T> &promise);
constexpr std::true_type is_promise_interface(const PromiseInterface<T> &promise) {
return {};
}
template <class T>
constexpr std::true_type is_promise_interface(const Promise<T> &promise);
constexpr std::true_type is_promise_interface(const Promise<T> &promise) {
return {};
}
template <class F>
constexpr bool is_promise_interface() {
return decltype(is_promise_interface(std::declval<F>()))::value;
}
constexpr std::false_type is_promise_interface_ptr(...);
constexpr inline std::false_type is_promise_interface_ptr(...) {
return {};
}
template <class T>
constexpr std::true_type is_promise_interface_ptr(const unique_ptr<T> &promise);
constexpr std::true_type is_promise_interface_ptr(const unique_ptr<T> &promise) {
return {};
}
template <class F>
constexpr bool is_promise_interface_ptr() {
@ -231,6 +241,7 @@ template <class T, class F, std::enable_if_t<is_promise_interface_ptr<F>(), bool
auto promise_interface_ptr(F &&f) {
return std::forward<F>(f);
}
template <class T, class F, std::enable_if_t<!is_promise_interface_ptr<F>(), bool> from_promise_interface = false>
auto promise_interface_ptr(F &&f) {
return td::make_unique<std::decay_t<decltype(promise_interface<T>(std::forward<F>(f)))>>(

View File

@ -688,8 +688,7 @@ Slice remove_fitzpatrick_modifier(Slice emoji) {
}
Slice remove_emoji_modifiers(Slice emoji) {
static const Slice modifiers[] = {u8"\uFE0E" /* variation selector-15 */,
u8"\uFE0F" /* variation selector-16 */,
static const Slice modifiers[] = {u8"\uFE0F" /* variation selector-16 */,
u8"\u200D\u2640" /* zero width joiner + female sign */,
u8"\u200D\u2642" /* zero width joiner + male sign */,
u8"\U0001F3FB" /* emoji modifier fitzpatrick type-1-2 */,
@ -714,4 +713,21 @@ void remove_emoji_modifiers_in_place(string &emoji) {
emoji.resize(remove_emoji_modifiers(emoji).size());
}
string remove_emoji_selectors(Slice emoji) {
if (!is_emoji(emoji)) {
return emoji.str();
}
string str;
for (size_t i = 0; i < emoji.size(); i++) {
if (i + 3 <= emoji.size() && emoji[i] == '\xEF' && emoji[i + 1] == '\xB8' && emoji[i + 2] == '\x8F') {
// skip \uFE0F
i += 2;
} else {
str += emoji[i];
}
}
CHECK(is_emoji(str));
return str;
}
} // namespace td

View File

@ -26,4 +26,7 @@ Slice remove_emoji_modifiers(Slice emoji);
// removes all emoji modifiers from the end of the string in place
void remove_emoji_modifiers_in_place(string &emoji);
// removes all emoji selectors from the string if it is an emoji
string remove_emoji_selectors(Slice emoji);
} // namespace td

View File

@ -29,25 +29,25 @@ TEST(Buffer, buffer_builder) {
}
{
auto str = td::rand_string('a', 'z', 10000);
auto splitted_str = td::rand_split(str);
auto split_str = td::rand_split(str);
int l = td::Random::fast(0, static_cast<int>(splitted_str.size() - 1));
int l = td::Random::fast(0, static_cast<int>(split_str.size() - 1));
int r = l;
td::BufferBuilder builder(splitted_str[l], 123, 1000);
while (l != 0 || r != static_cast<int>(splitted_str.size()) - 1) {
if (l == 0 || (td::Random::fast_bool() && r != static_cast<int>(splitted_str.size() - 1))) {
td::BufferBuilder builder(split_str[l], 123, 1000);
while (l != 0 || r != static_cast<int>(split_str.size()) - 1) {
if (l == 0 || (td::Random::fast_bool() && r != static_cast<int>(split_str.size() - 1))) {
r++;
if (td::Random::fast_bool()) {
builder.append(splitted_str[r]);
builder.append(split_str[r]);
} else {
builder.append(td::BufferSlice(splitted_str[r]));
builder.append(td::BufferSlice(split_str[r]));
}
} else {
l--;
if (td::Random::fast_bool()) {
builder.prepend(splitted_str[l]);
builder.prepend(split_str[l]);
} else {
builder.prepend(td::BufferSlice(splitted_str[l]));
builder.prepend(td::BufferSlice(split_str[l]));
}
}
}

View File

@ -43,7 +43,6 @@
#include <algorithm>
#include <atomic>
#include <clocale>
#include <limits>
#include <locale>
#include <unordered_map>
@ -476,8 +475,7 @@ static void test_to_double() {
TEST(Misc, to_double) {
test_to_double();
const char *locale_name = (std::setlocale(LC_ALL, "fr-FR") == nullptr ? "C" : "fr-FR");
std::locale new_locale(locale_name);
std::locale new_locale("C");
auto host_locale = std::locale::global(new_locale);
test_to_double();
new_locale = std::locale::global(std::locale::classic());

View File

@ -868,7 +868,7 @@ TEST(Client, Simple) {
}
TEST(Client, SimpleMulti) {
std::vector<td::Client> clients(40);
std::vector<td::Client> clients(7);
//for (auto &client : clients) {
//client.execute({1, td::td_api::make_object<td::td_api::setLogTagVerbosityLevel>("td_requests", 1)});
//}