Merge commit '3aee3527511ce43ae670081f3f65a71e7c92ee2c'

Conflicts:
	td/telegram/MessagesDb.cpp
This commit is contained in:
Andrea Cavalli 2020-10-01 11:42:54 +02:00
commit 24ee424c91
57 changed files with 2209 additions and 595 deletions

View File

@ -1,4 +1,4 @@
Changes in 1.6.0:
Changes in 1.6.0 (31 Jan 2020):
* Added support for multiple chat lists. Currently, only two chat lists Main and Archive are supported:
- Added the class `ChatList`, which represents a chat list and could be `chatListMain` or `chatListArchive`.
@ -61,7 +61,7 @@ Changes in 1.6.0:
- Added the field `type` to the classes `poll` and `inputMessagePoll`.
- Added support for non-anonymous polls with visible votes by adding the field `is_anonymous` to the classes `poll`
and `inputMessagePoll`.
- Added the method `getPollVoters`, returning users that voted for the specified option in a non-anonymous poll.
- Added the method `getPollVoters` returning users that voted for the specified option in a non-anonymous poll.
- Added the new reply markup keyboard button `keyboardButtonTypeRequestPoll`.
- Added the field `is_regular` to the class `pushMessageContentPoll`.
- Added the update `updatePollAnswer` for bots only.
@ -172,7 +172,7 @@ Changes in 1.6.0:
-----------------------------------------------------------------------------------------------------------------------
Changes in 1.5.0:
Changes in 1.5.0 (9 Sep 2019):
* Changed authorization workflow:
- Added the state `authorizationStateWaitRegistration`, which will be received after `authorizationStateWaitCode` for
@ -250,7 +250,7 @@ Changes in 1.5.0:
- Added the field `audio_cover_minithumbnail` to the class `audio`.
* Added support for resending messages which failed to send:
- Added the fields `error_code`, `error_message`, `can_retry` and `retry_after` to
the `messageSendingStateFailed` object.
the class `messageSendingStateFailed`.
- Added the method `resendMessages`.
* Added the field `is_animated` to the `sticker`, `stickerSet` and `stickerSetInfo` classes.
Animated stickers can be received anywhere where non-animated stickers can appear.
@ -278,7 +278,7 @@ Changes in 1.5.0:
-----------------------------------------------------------------------------------------------------------------------
Changes in 1.4.0:
Changes in 1.4.0 (1 May 2019):
* Added a [TDLib build instructions generator](https://tdlib.github.io/td/build.html), covering in details
TDLib building on the most popular operating systems.
@ -532,7 +532,7 @@ Changes in 1.4.0:
-----------------------------------------------------------------------------------------------------------------------
Changes in 1.3.0:
Changes in 1.3.0 (5 Sep 2018):
* Added a review of existing TDLib based [frameworks](https://github.com/tdlib/td/blob/master/example/README.md)
in different programming languages.
@ -678,7 +678,7 @@ Changes in 1.3.0:
-----------------------------------------------------------------------------------------------------------------------
Changes in 1.2.0:
Changes in 1.2.0 (20 Mar 2018):
* Added support for native .NET bindings through `C++/CLI` and `C++/CX`.
See [using in .NET projects](README.md#using-dotnet) for more details.
@ -725,13 +725,13 @@ Changes in 1.2.0:
-----------------------------------------------------------------------------------------------------------------------
Changes in 1.1.1:
Changes in 1.1.1 (4 Feb 2018):
* Fixed C JSON bindings compilation error.
* Fixed locale-dependent JSON generation.
-----------------------------------------------------------------------------------------------------------------------
Changes in 1.1.0:
Changes in 1.1.0 (31 Jan 2018):
* Methods `td::Log::set_file_path` and `td_set_log_file_path` now return whether they succeeded.
* Added methods `td::Log::set_max_file_size` and `td_set_log_max_file_size` for restricting maximum TDLib log size.

View File

@ -399,6 +399,7 @@ set(TDLIB_SOURCE
td/telegram/ConfigShared.cpp
td/telegram/Contact.cpp
td/telegram/ContactsManager.cpp
td/telegram/CountryInfoManager.cpp
td/telegram/DelayDispatcher.cpp
td/telegram/Dependencies.cpp
td/telegram/DeviceTokenManager.cpp
@ -447,7 +448,9 @@ set(TDLIB_SOURCE
td/telegram/MessageContentType.cpp
td/telegram/MessageEntity.cpp
td/telegram/MessageId.cpp
td/telegram/MessageReplyInfo.cpp
td/telegram/MessagesDb.cpp
td/telegram/MessageSearchFilter.cpp
td/telegram/MessagesManager.cpp
td/telegram/misc.cpp
td/telegram/net/AuthDataShared.cpp
@ -553,6 +556,7 @@ set(TDLIB_SOURCE
td/telegram/ConfigShared.h
td/telegram/Contact.h
td/telegram/ContactsManager.h
td/telegram/CountryInfoManager.h
td/telegram/DelayDispatcher.h
td/telegram/Dependencies.h
td/telegram/DeviceTokenManager.h
@ -618,7 +622,9 @@ set(TDLIB_SOURCE
td/telegram/MessageCopyOptions.h
td/telegram/MessageEntity.h
td/telegram/MessageId.h
td/telegram/MessageReplyInfo.h
td/telegram/MessagesDb.h
td/telegram/MessageSearchFilter.h
td/telegram/MessagesManager.h
td/telegram/misc.h
td/telegram/net/AuthDataShared.h

View File

@ -14,6 +14,7 @@
#include "td/utils/UInt.h"
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <array>
#include <atomic>
@ -164,6 +165,47 @@ class AesCtrBench : public td::Benchmark {
}
};
class AesCtrOpenSSLBench : public td::Benchmark {
public:
alignas(64) unsigned char data[DATA_SIZE];
alignas(64) unsigned char dest[DATA_SIZE];
td::UInt256 key;
td::UInt128 iv;
std::string get_description() const override {
return PSTRING() << "AES CTR RAW OpenSSL [" << (DATA_SIZE >> 10) << "KB]";
}
void start_up() override {
for (int i = 0; i < DATA_SIZE; i++) {
data[i] = 123;
}
td::Random::secure_bytes(key.raw, sizeof(key));
td::Random::secure_bytes(iv.raw, sizeof(iv));
}
void run(int n) override {
EVP_CIPHER_CTX *ctx;
int len;
ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, key.raw, iv.raw);
td::MutableSlice data_slice(data, DATA_SIZE);
td::MutableSlice dest_slice(dest, DATA_SIZE);
td::AesCtrState state;
state.init(as_slice(key), as_slice(iv));
for (int i = 0; i < n; i++) {
//state.encrypt(data_slice, data_slice);
len = (int)data_slice.size();
EVP_EncryptUpdate(ctx, dest_slice.ubegin(), &len, data_slice.ubegin(), len);
}
//EVP_EncryptFinal_ex(ctx, ciphertext + len, &len);
EVP_CIPHER_CTX_free(ctx);
}
};
class AesCbcBench : public td::Benchmark {
public:
alignas(64) unsigned char data[DATA_SIZE];
@ -346,13 +388,14 @@ class Crc64Bench : public td::Benchmark {
int main() {
td::init_openssl_threads();
td::bench(AesCtrBench());
td::bench(AesCtrOpenSSLBench());
td::bench(AesIgeShortBench<true>());
td::bench(AesIgeShortBench<false>());
td::bench(AesIgeEncryptBench());
td::bench(AesIgeDecryptBench());
td::bench(AesEcbBench());
td::bench(AesCtrBench());
td::bench(Pbkdf2Bench());
td::bench(RandBench());

View File

@ -178,8 +178,10 @@ inputFileLocal path:string = InputFile;
inputFileGenerated original_path:string conversion:string expected_size:int32 = InputFile;
//@description Photo description @type Thumbnail type (see https://core.telegram.org/constructor/photoSize) @photo Information about the photo file @width Photo width @height Photo height
photoSize type:string photo:file width:int32 height:int32 = PhotoSize;
//@description Describes an image in JPEG format @type Image type (see https://core.telegram.org/constructor/photoSize)
//@photo Information about the image file @width Image width @height Image height
//@progressive_sizes Sizes of progressive JPEG file prefixes, which can be used to preliminarily show the image
photoSize type:string photo:file width:int32 height:int32 progressive_sizes:vector<int32> = PhotoSize;
//@description Thumbnail image of a very poor quality and low resolution @width Thumbnail width, usually doesn't exceed 40 @height Thumbnail height, usually doesn't exceed 40 @data The thumbnail in JPEG format
minithumbnail width:int32 height:int32 data:bytes = Minithumbnail;
@ -293,7 +295,7 @@ contact phone_number:string first_name:string last_name:string vcard:string user
//@description Describes a location on planet Earth @latitude Latitude of the location in degrees; as defined by the sender @longitude Longitude of the location, in degrees; as defined by the sender
location latitude:double longitude:double = Location;
//@description Describes a venue @location Venue location; as defined by the sender @title Venue name; as defined by the sender @address Venue address; as defined by the sender @provider Provider of the venue database; as defined by the sender. Currently only "foursquare" and "gplaces" (Google Places) needs to be supported
//@description Describes a venue @location Venue location; as defined by the sender @title Venue name; as defined by the sender @address Venue address; as defined by the sender @provider Provider of the venue database; as defined by the sender. Currently only "foursquare" and "gplaces" (Google Places) need to be supported
//@id Identifier of the venue in the provider database; as defined by the sender @type Type of the venue in the provider database; as defined by the sender
venue location:location title:string address:string provider:string id:string type:string = Venue;
@ -352,7 +354,7 @@ chatLocation location:location address:string = ChatLocation;
//@description Animated variant of a chat photo in MPEG4 format
//@length Animation width and height
//@file Information about the animation file
//@main_frame_timestamp Timestamp of the frame, used as static chat photo
//@main_frame_timestamp Timestamp of the frame, used as a static chat photo
animatedChatPhoto length:int32 file:file main_frame_timestamp:double = AnimatedChatPhoto;
@ -428,7 +430,7 @@ chatAdministrators administrators:vector<chatAdministrator> = ChatAdministrators
//@can_send_messages True, if the user can send text messages, contacts, locations, and venues
//@can_send_media_messages True, if the user can send audio files, documents, photos, videos, video notes, and voice notes. Implies can_send_messages permissions
//@can_send_polls True, if the user can send polls. Implies can_send_messages permissions
//@can_send_other_messages True, if the user can send animations, games, stickers and dice and use inline bots. Implies can_send_messages permissions
//@can_send_other_messages True, if the user can send animations, games, stickers, and dice and use inline bots. Implies can_send_messages permissions
//@can_add_web_page_previews True, if the user may add a web page preview to their messages. Implies can_send_messages permissions
//@can_change_info True, if the user can change the chat title, photo, and other settings
//@can_invite_users True, if the user can invite new users to the chat
@ -475,9 +477,9 @@ chatMemberStatusBanned banned_until_date:int32 = ChatMemberStatus;
//@description A user with information about joining/leaving a chat @user_id User identifier of the chat member
//@inviter_user_id Identifier of a user that invited/promoted/banned this member in the chat; 0 if unknown
//@joined_chat_date Point in time (Unix timestamp) when the user joined a chat
//@joined_chat_date Point in time (Unix timestamp) when the user joined the chat
//@status Status of the member in the chat
//@bot_info If the user is a bot, information about the bot; may be null. Can be null even for a bot if the bot is not a chat member
//@bot_info If the user is a bot, information about the bot; may be null. Can be null even for a bot if the bot is not the chat member
chatMember user_id:int32 inviter_user_id:int32 joined_chat_date:int32 status:ChatMemberStatus bot_info:botInfo = ChatMember;
//@description Contains a list of chat members @total_count Approximate total count of chat members found @members A list of chat members
@ -576,14 +578,14 @@ supergroup id:int32 username:string date:int32 status:ChatMemberStatus member_co
//@can_set_username True, if the chat username can be changed
//@can_set_sticker_set True, if the supergroup sticker set can be changed
//@can_set_location True, if the supergroup location can be changed
//@can_view_statistics True, if the channel statistics is available
//@can_get_statistics True, if the supergroup or channel statistics are available
//@is_all_history_available True, if new chat members will have access to old messages. In public or discussion groups and both public and private channels, old messages are always available, so this option affects only private supergroups without a linked chat. The value of this field is only available for chat administrators
//@sticker_set_id Identifier of the supergroup sticker set; 0 if none
//@location Location to which the supergroup is connected; may be null
//@invite_link Invite link for this chat
//@upgraded_from_basic_group_id Identifier of the basic group from which supergroup was upgraded; 0 if none
//@upgraded_from_max_message_id Identifier of the last message in the basic group from which supergroup was upgraded; 0 if none
supergroupFullInfo photo:chatPhoto description:string member_count:int32 administrator_count:int32 restricted_count:int32 banned_count:int32 linked_chat_id:int53 slow_mode_delay:int32 slow_mode_delay_expires_in:double can_get_members:Bool can_set_username:Bool can_set_sticker_set:Bool can_set_location:Bool can_view_statistics:Bool is_all_history_available:Bool sticker_set_id:int64 location:chatLocation invite_link:string upgraded_from_basic_group_id:int32 upgraded_from_max_message_id:int53 = SupergroupFullInfo;
supergroupFullInfo photo:chatPhoto description:string member_count:int32 administrator_count:int32 restricted_count:int32 banned_count:int32 linked_chat_id:int53 slow_mode_delay:int32 slow_mode_delay_expires_in:double can_get_members:Bool can_set_username:Bool can_set_sticker_set:Bool can_set_location:Bool can_get_statistics:Bool is_all_history_available:Bool sticker_set_id:int64 location:chatLocation invite_link:string upgraded_from_basic_group_id:int32 upgraded_from_max_message_id:int53 = SupergroupFullInfo;
//@class SecretChatState @description Describes the current secret chat state
@ -633,6 +635,13 @@ messageForwardOriginChannel chat_id:int53 message_id:int53 author_signature:stri
//@from_message_id For messages forwarded to the chat with the current user (Saved Messages) or to the channel's discussion group, the identifier of the original message from which the new message was forwarded last time; 0 if unknown
messageForwardInfo origin:MessageForwardOrigin date:int32 public_service_announcement_type:string from_chat_id:int53 from_message_id:int53 = MessageForwardInfo;
//@description Contains information about interactions with a message
//@view_count Number of times the message was viewed
//@forward_count Number of times the message was forwarded
//@reply_count Number of times the message was directly or indirectly replied; supergroups and linked channels only
//@recent_replier_user_ids User identifiers of the recent repliers to the message
messageInteractionInfo view_count:int32 forward_count:int32 reply_count:int32 recent_replier_user_ids:vector<int32> = MessageInteractionInfo;
//@class MessageSendingState @description Contains information about the sending state of the message
@ -655,28 +664,30 @@ messageSendingStateFailed error_code:int32 error_message:string can_retry:Bool r
//@can_be_forwarded True, if the message can be forwarded
//@can_be_deleted_only_for_self True, if the message can be deleted only for the current user while other users will continue to see it
//@can_be_deleted_for_all_users True, if the message can be deleted for all users
//@can_get_statistics True, if the message statistics are available
//@can_get_replies True, if the message replies are available
//@is_channel_post True, if the message is a channel post. All messages to channels are channel posts, all other messages are not channel posts
//@contains_unread_mention True, if the message contains an unread mention for the current user
//@date Point in time (Unix timestamp) when the message was sent
//@edit_date Point in time (Unix timestamp) when the message was last edited
//@forward_info Information about the initial message sender; may be null
//@interaction_info Information about interactions with the message; may be null
//@reply_to_message_id If non-zero, the identifier of the message this message is replying to; can be the identifier of a deleted message
//@ttl For self-destructing messages, the message's TTL (Time To Live), in seconds; 0 if none. TDLib will send updateDeleteMessages or updateMessageContent once the TTL expires
//@ttl_expires_in Time left before the message expires, in seconds
//@via_bot_user_id If non-zero, the user identifier of the bot through which this message was sent
//@author_signature For channel posts, optional author signature
//@views Number of times this message was viewed
//@media_album_id Unique identifier of an album this message belongs to. Only photos and videos can be grouped together in albums
//@restriction_reason If non-empty, contains a human-readable description of the reason why access to this message must be restricted
//@content Content of the message
//@reply_markup Reply markup for the message; may be null
message id:int53 sender_user_id:int32 chat_id:int53 sending_state:MessageSendingState scheduling_state:MessageSchedulingState is_outgoing:Bool can_be_edited:Bool can_be_forwarded:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool is_channel_post:Bool contains_unread_mention:Bool date:int32 edit_date:int32 forward_info:messageForwardInfo reply_to_message_id:int53 ttl:int32 ttl_expires_in:double via_bot_user_id:int32 author_signature:string views:int32 media_album_id:int64 restriction_reason:string content:MessageContent reply_markup:ReplyMarkup = Message;
message id:int53 sender_user_id:int32 chat_id:int53 sending_state:MessageSendingState scheduling_state:MessageSchedulingState is_outgoing:Bool can_be_edited:Bool can_be_forwarded:Bool can_be_deleted_only_for_self:Bool can_be_deleted_for_all_users:Bool can_get_statistics:Bool can_get_replies:Bool is_channel_post:Bool contains_unread_mention:Bool date:int32 edit_date:int32 forward_info:messageForwardInfo interaction_info:messageInteractionInfo reply_to_message_id:int53 ttl:int32 ttl_expires_in:double via_bot_user_id:int32 author_signature:string media_album_id:int64 restriction_reason:string content:MessageContent reply_markup:ReplyMarkup = Message;
//@description Contains a list of messages @total_count Approximate total count of messages found @messages List of messages; messages may be null
messages total_count:int32 messages:vector<message> = Messages;
//@description Contains a list of messages found by a search @messages List of messages @next_from_search_id Value to pass as from_search_id to get more results
foundMessages messages:vector<message> next_from_search_id:int64 = FoundMessages;
//@description Contains a list of messages found by a search @total_count Approximate total count of messages found; -1 if unknown @messages List of messages @next_offset The offset for the next request. If empty, there are no more results
foundMessages total_count:int32 messages:vector<message> next_offset:string = FoundMessages;
//@class NotificationSettingsScope @description Describes the types of chats to which notification settings are applied
@ -833,7 +844,7 @@ chatsNearby users_nearby:vector<chatNearby> supergroups_nearby:vector<chatNearby
chatInviteLink invite_link:string = ChatInviteLink;
//@description Contains information about a chat invite link
//@chat_id Chat identifier of the invite link; 0 if the user have no access to the chat before joining
//@chat_id Chat identifier of the invite link; 0 if the user has no access to the chat before joining
//@accessible_for If non-zero, the remaining time for which read access is granted to the chat, in seconds
//@type Contains information about the type of the chat
//@title Title of the chat
@ -901,10 +912,13 @@ inlineKeyboardButtonTypeUrl url:string = InlineKeyboardButtonType;
//@description A button that opens a specified URL and automatically logs in in current user if they allowed to do that @url An HTTP URL to open @id Unique button identifier @forward_text If non-empty, new text of the button in forwarded messages
inlineKeyboardButtonTypeLoginUrl url:string id:int32 forward_text:string = InlineKeyboardButtonType;
//@description A button that sends a special callback query to a bot @data Data to be sent to the bot via a callback query
//@description A button that sends a callback query to a bot @data Data to be sent to the bot via a callback query
inlineKeyboardButtonTypeCallback data:bytes = InlineKeyboardButtonType;
//@description A button with a game that sends a special callback query to a bot. This button must be in the first column and row of the keyboard and can be attached only to a message with content of the type messageGame
//@description A button that asks for password of the current user and then sends a callback query to a bot @data Data to be sent to the bot via a callback query
inlineKeyboardButtonTypeCallbackWithPassword data:bytes = InlineKeyboardButtonType;
//@description A button with a game that sends a callback query to a bot. This button must be in the first column and row of the keyboard and can be attached only to a message with content of the type messageGame
inlineKeyboardButtonTypeCallbackGame = InlineKeyboardButtonType;
//@description A button that forces an inline query to the bot to be inserted in the input field @query Inline query to be sent to the bot @in_current_chat True, if the inline query should be sent from the current chat
@ -1168,6 +1182,24 @@ webPageInstantView page_blocks:vector<PageBlock> view_count:int32 version:int32
webPage url:string display_url:string type:string site_name:string title:string description:formattedText photo:photo embed_url:string embed_type:string embed_width:int32 embed_height:int32 duration:int32 author:string animation:animation audio:audio document:document sticker:sticker video:video video_note:videoNote voice_note:voiceNote instant_view_version:int32 = WebPage;
//@description Contains information about a country
//@country_code A two-letter ISO 3166-1 alpha-2 country code
//@name Native name of the country
//@english_name English name of the country
//@is_hidden True, if the country should be hidden from the list of all countries
//@calling_codes List of country calling codes
countryInfo country_code:string name:string english_name:string is_hidden:Bool calling_codes:vector<string> = CountryInfo;
//@description Contains information about countries @countries The list of countries
countries countries:vector<countryInfo> = Countries;
//@description Contains information about a phone number
//@country Information about the country to which the phone number belongs; may be null
//@country_calling_code The part of the phone number denoting country calling code or its part
//@formatted_phone_number The phone number without country calling code formatted accordingly to local rules
phoneNumberInfo country:countryInfo country_calling_code:string formatted_phone_number:string = PhoneNumberInfo;
//@description Describes an action associated with a bank card number @text Action text @url The URL to be opened
bankCardActionOpenUrl text:string url:string = BankCardActionOpenUrl;
@ -1684,7 +1716,7 @@ messageSchedulingStateSendWhenOnline = MessageSchedulingState;
//@description Options to be used when a message is sent
//@disable_notification Pass true to disable notification for the message. Must be false if the message is sent to a secret chat
//@disable_notification Pass true to disable notification for the message
//@from_background Pass true if the message is sent from the background
//@scheduling_state Message scheduling state. Messages sent to a secret chat, live location messages and self-destructing messages can't be scheduled
messageSendOptions disable_notification:Bool from_background:Bool scheduling_state:MessageSchedulingState = MessageSendOptions;
@ -1980,6 +2012,12 @@ callProblemSilentRemote = CallProblem;
//@description The call ended unexpectedly
callProblemDropped = CallProblem;
//@description The video was distorted
callProblemDistortedVideo = CallProblem;
//@description The video was pixelated
callProblemPixelatedVideo = CallProblem;
//@description Describes a call @id Call identifier, not persistent @user_id Peer user identifier @is_outgoing True, if the call is outgoing @is_video True, if the call is a video call @state Call state
call id:int32 user_id:int32 is_outgoing:Bool is_video:Bool state:CallState = Call;
@ -1988,7 +2026,7 @@ call id:int32 user_id:int32 is_outgoing:Bool is_video:Bool state:CallState = Cal
//@description Contains settings for the authentication of the user's phone number
//@allow_flash_call Pass true if the authentication code may be sent via flash call to the specified phone number
//@is_current_phone_number Pass true if the authenticated phone number is used on the current device
//@allow_sms_retriever_api For official applications only. True, if the app can use Android SMS Retriever API (requires Google Play Services >= 10.2) to automatically receive the authentication code from the SMS. See https://developers.google.com/identity/sms-retriever/ for more details
//@allow_sms_retriever_api For official applications only. True, if the application can use Android SMS Retriever API (requires Google Play Services >= 10.2) to automatically receive the authentication code from the SMS. See https://developers.google.com/identity/sms-retriever/ for more details
phoneNumberAuthenticationSettings allow_flash_call:Bool is_current_phone_number:Bool allow_sms_retriever_api:Bool = PhoneNumberAuthenticationSettings;
@ -2125,10 +2163,13 @@ inlineQueryResults inline_query_id:int64 next_offset:string results:vector<Inlin
//@class CallbackQueryPayload @description Represents a payload of a callback query
//@description The payload from a general callback button @data Data that was attached to the callback button
//@description The payload for a general callback button @data Data that was attached to the callback button
callbackQueryPayloadData data:bytes = CallbackQueryPayload;
//@description The payload from a game callback button @game_short_name A short name of the game that was attached to the callback button
//@description The payload for a callback button requiring password @password The password for the current user@data Data that was attached to the callback button
callbackQueryPayloadDataWithPassword password:string data:bytes = CallbackQueryPayload;
//@description The payload for a game callback button @game_short_name A short name of the game that was attached to the callback button
callbackQueryPayloadGame game_short_name:string = CallbackQueryPayload;
@ -2269,7 +2310,7 @@ languagePackInfo id:string base_language_pack_id:string name:string native_name:
localizationTargetInfo language_packs:vector<languagePackInfo> = LocalizationTargetInfo;
//@class DeviceToken @description Represents a data needed to subscribe for push notifications through registerDevice method. To use specific push notification service, you must specify the correct application platform and upload valid server authentication data at https://my.telegram.org
//@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 should be additionally encrypted
deviceTokenFirebaseCloudMessaging token:string encrypt:Bool = DeviceToken;
@ -2791,7 +2832,7 @@ networkStatisticsEntryFile file_type:FileType network_type:NetworkType sent_byte
//@sent_bytes Total number of bytes sent @received_bytes Total number of bytes received @duration Total call duration, in seconds
networkStatisticsEntryCall network_type:NetworkType sent_bytes:int53 received_bytes:int53 duration:double = NetworkStatisticsEntry;
//@description A full list of available network statistic entries @since_date Point in time (Unix timestamp) when the app began collecting statistics @entries Network statistics entries
//@description A full list of available network statistic entries @since_date Point in time (Unix timestamp) from which the statistics are collected @entries Network statistics entries
networkStatistics since_date:int32 entries:vector<NetworkStatisticsEntry> = NetworkStatistics;
@ -2801,7 +2842,7 @@ networkStatistics since_date:int32 entries:vector<NetworkStatisticsEntry> = Netw
//@max_video_file_size The maximum size of a video file to be auto-downloaded
//@max_other_file_size The maximum size of other file types to be auto-downloaded
//@video_upload_bitrate The maximum suggested bitrate for uploaded videos
//@preload_large_videos True, if the beginning of videos needs to be preloaded for instant playback
//@preload_large_videos True, if the beginning of video files needs to be preloaded for instant playback
//@preload_next_audio True, if the next audio track needs to be preloaded while the user is listening to an audio file
//@use_less_data_for_calls True, if "use less data for calls" option needs to be enabled
autoDownloadSettings is_auto_download_enabled:Bool max_photo_file_size:int32 max_video_file_size:int32 max_other_file_size:int32 video_upload_bitrate:int32 preload_large_videos:Bool preload_next_audio:Bool use_less_data_for_calls:Bool = AutoDownloadSettings;
@ -2955,7 +2996,7 @@ statisticsValue value:double previous_value:double growth_rate_percentage:double
//@description A graph data @json_data Graph data in JSON format @zoom_token If non-empty, a token which can be used to receive a zoomed in graph
statisticsGraphData json_data:string zoom_token:string = StatisticsGraph;
//@description The graph data to be asynchronously loaded through getChatStatisticsGraph @token The token to use for data loading
//@description The graph data to be asynchronously loaded through getStatisticsGraph @token The token to use for data loading
statisticsGraphAsync token:string = StatisticsGraph;
//@description An error message to be shown to the user instead of the graph @error_message The error message
@ -3027,6 +3068,10 @@ chatStatisticsSupergroup period:dateRange member_count:statisticsValue message_c
chatStatisticsChannel period:dateRange member_count:statisticsValue mean_view_count:statisticsValue mean_share_count:statisticsValue enabled_notifications_percentage:double member_count_graph:StatisticsGraph join_graph:StatisticsGraph mute_graph:StatisticsGraph view_count_by_hour_graph:StatisticsGraph view_count_by_source_graph:StatisticsGraph join_by_source_graph:StatisticsGraph language_graph:StatisticsGraph message_interaction_graph:StatisticsGraph instant_view_interaction_graph:StatisticsGraph recent_message_interactions:vector<chatStatisticsMessageInteractionInfo> = ChatStatistics;
//@description A detailed statistics about a message @message_interaction_graph A graph containing number of message views and shares
messageStatistics message_interaction_graph:StatisticsGraph = MessageStatistics;
//@class Update @description Contains notifications about data changes
//@description The user authorization state has changed @authorization_state New authorization state
@ -3052,8 +3097,8 @@ updateMessageContent chat_id:int53 message_id:int53 new_content:MessageContent =
//@description A message was edited. Changes in the message content will come in a separate updateMessageContent @chat_id Chat identifier @message_id Message identifier @edit_date Point in time (Unix timestamp) when the message was edited @reply_markup New message reply markup; may be null
updateMessageEdited chat_id:int53 message_id:int53 edit_date:int32 reply_markup:ReplyMarkup = Update;
//@description The view count of the message has changed @chat_id Chat identifier @message_id Message identifier @views New value of the view count
updateMessageViews chat_id:int53 message_id:int53 views:int32 = Update;
//@description The information about interactions with a message has changed @chat_id Chat identifier @message_id Message identifier @interaction_info New information about interactions with the message
updateMessageInteractionInfo chat_id:int53 message_id:int53 interaction_info:messageInteractionInfo = Update;
//@description The message content was opened. Updates voice note messages to "listened", video note messages to "viewed" and starts the TTL timer for self-destructing messages @chat_id Chat identifier @message_id Message identifier
updateMessageContentOpened chat_id:int53 message_id:int53 = Update;
@ -3574,15 +3619,17 @@ searchChatMessages chat_id:int53 query:string sender_user_id:int32 from_message_
//@offset_date The date of the message starting from which the results should be fetched. Use 0 or any date in the future to get results from the last message
//@offset_chat_id The chat identifier of the last found message, or 0 for the first request
//@offset_message_id The message identifier of the last found message, or 0 for the first request
//@limit The maximum number of messages to be returned, up to 100. Fewer messages may be returned than specified by the limit, even if the end of the message history has not been reached
searchMessages chat_list:ChatList query:string offset_date:int32 offset_chat_id:int53 offset_message_id:int53 limit:int32 = Messages;
//@limit The maximum number of messages to be returned; up to 100. Fewer messages may be returned than specified by the limit, even if the end of the message history has not been reached
//@filter Filter for message content in the search results; searchMessagesFilterCall, searchMessagesFilterMissedCall, searchMessagesFilterMention, searchMessagesFilterUnreadMention and searchMessagesFilterFailedToSend are unsupported in this function
searchMessages chat_list:ChatList query:string offset_date:int32 offset_chat_id:int53 offset_message_id:int53 limit:int32 filter:SearchMessagesFilter = Messages;
//@description Searches for messages in secret chats. Returns the results in reverse chronological order. For optimal performance the number of returned messages is chosen by the library
//@chat_id Identifier of the chat in which to search. Specify 0 to search in all secret chats @query Query to search for. If empty, searchChatMessages should be used instead
//@from_search_id The identifier from the result of a previous request, use 0 to get results from the last message
//@chat_id Identifier of the chat in which to search. Specify 0 to search in all secret chats
//@query Query to search for. If empty, searchChatMessages should be used instead
//@offset Offset of the first entry to return as received from the previous request; use empty string to get first chunk of results
//@limit The maximum number of messages to be returned; up to 100. Fewer messages may be returned than specified by the limit, even if the end of the message history has not been reached
//@filter A filter for the content of messages in the search results
searchSecretMessages chat_id:int53 query:string from_search_id:int64 limit:int32 filter:SearchMessagesFilter = FoundMessages;
//@filter A filter for message content in the search results
searchSecretMessages chat_id:int53 query:string offset:string limit:int32 filter:SearchMessagesFilter = FoundMessages;
//@description Searches for call messages. Returns the results in reverse chronological order (i. e., in order of decreasing message_id). For optimal performance the number of returned messages is chosen by the library
//@from_message_id Identifier of the message from which to search; use 0 to get results from the last message
@ -3604,6 +3651,13 @@ getChatMessageCount chat_id:int53 filter:SearchMessagesFilter return_local:Bool
//@description Returns all scheduled messages in a chat. The messages are returned in a reverse chronological order (i.e., in order of decreasing message_id) @chat_id Chat identifier
getChatScheduledMessages chat_id:int53 = Messages;
//@description Returns forwarded copies of a channel message to another public channels. For optimal performance the number of returned messages is chosen by the library
//@chat_id Chat identifier of the message
//@message_id Message identifier
//@offset Offset of the first entry to return as received from the previous request; use empty string to get first chunk of results
//@limit The maximum number of messages to be returned; must be positive and can't be greater than 100. Fewer messages may be returned than specified by the limit, even if the end of the list has not been reached
getMessagePublicForwards chat_id:int53 message_id:int53 offset:string limit:int32 = FoundMessages;
//@description Removes an active notification from notification list. Needs to be called only if the notification is removed by the current user @notification_group_id Identifier of notification group to which the notification belongs @notification_id Identifier of removed notification
removeNotification notification_group_id:int32 notification_id:int32 = Ok;
@ -3655,7 +3709,7 @@ sendInlineQueryResultMessage chat_id:int53 reply_to_message_id:int53 options:mes
//@options Options to be used to send the messages
//@as_album True, if the messages should be grouped into an album after forwarding. For this to work, no more than 10 messages may be forwarded, and all of them must be photo or video messages
//@send_copy True, if content of the messages needs to be copied without links to the original messages. Always true if the messages are forwarded to a secret chat
//@remove_caption True, if media captions of message copies needs to be removed. Ignored if send_copy is false
//@remove_caption True, if media caption of message copies needs to be removed. Ignored if send_copy is false
forwardMessages chat_id:int53 from_chat_id:int53 message_ids:vector<int53> options:messageSendOptions as_album:Bool send_copy:Bool remove_caption:Bool = Messages;
//@description Resends messages which failed to send. Can be called only for messages for which messageSendingStateFailed.can_retry is true and after specified in messageSendingStateFailed.retry_after time passed.
@ -3910,7 +3964,7 @@ getChatFilterDefaultIconName filter:chatFilter = Text;
setChatTitle chat_id:int53 title:string = Ok;
//@description Changes the photo of a chat. Supported only for basic groups, supergroups and channels. Requires can_change_info rights
//@chat_id Chat identifier @photo New chat photo. You can pass null to delete the chat photo
//@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 chat members permissions. Supported only for basic groups and supergroups. Requires can_restrict_members administrator right
@ -3937,7 +3991,7 @@ setChatClientData chat_id:int53 client_data:string = Ok;
setChatDescription chat_id:int53 description:string = Ok;
//@description Changes the discussion group of a channel chat; requires can_change_info rights in the channel if it is specified @chat_id Identifier of the channel chat. Pass 0 to remove a link from the supergroup passed in the second argument to a linked channel chat (requires can_pin_messages rights in the supergroup) @discussion_chat_id Identifier of a new channel's discussion group. Use 0 to remove the discussion group.
//-Use the method getSuitableDiscussionChats to find all suitable groups. Basic group chats needs to be first upgraded to supergroup chats. If new chat members don't have access to old messages in the supergroup, then toggleSupergroupIsAllHistoryAvailable needs to be used first to change that
//-Use the method getSuitableDiscussionChats to find all suitable groups. Basic group chats need to be first upgraded to supergroup chats. If new chat members don't have access to old messages in the supergroup, then toggleSupergroupIsAllHistoryAvailable needs to be used first to change that
setChatDiscussionGroup chat_id:int53 discussion_chat_id:int53 = Ok;
//@description Changes the location of a chat. Available only for some location-based supergroups, use supergroupFullInfo.can_set_location to check whether the method is allowed to use @chat_id Chat identifier @location New location for the chat; must be valid and not null
@ -4005,7 +4059,7 @@ setScopeNotificationSettings scope:NotificationSettingsScope notification_settin
resetAllNotificationSettings = Ok;
//@description Changes the pinned state of a chat. You can pin up to GetOption("pinned_chat_count_max")/GetOption("pinned_archived_chat_count_max") non-secret chats and the same number of secret chats in the main/arhive chat list
//@description Changes the pinned state of a chat. There can be up to GetOption("pinned_chat_count_max")/GetOption("pinned_archived_chat_count_max") pinned non-secret chats and the same number of secret chats in the main/arhive chat list
//@chat_list Chat list in which to change the pinned state of the chat @chat_id Chat identifier @is_pinned True, if the chat is pinned
toggleChatIsPinned chat_list:ChatList chat_id:int53 is_pinned:Bool = Ok;
@ -4351,7 +4405,7 @@ deleteSavedCredentials = Ok;
getSupportUser = User;
//@description Returns backgrounds installed by the user @for_dark_theme True, if the backgrounds needs to be ordered for dark theme
//@description Returns backgrounds installed by the user @for_dark_theme True, if the backgrounds need to be ordered for dark theme
getBackgrounds for_dark_theme:Bool = Backgrounds;
//@description Constructs a persistent HTTP URL for a background @name Background name @type Background type
@ -4449,14 +4503,17 @@ removeChatActionBar chat_id:int53 = Ok;
reportChat chat_id:int53 reason:ChatReportReason message_ids:vector<int53> = Ok;
//@description Returns an HTTP URL with the chat statistics. Currently this method of getting the statistics is disabled and can be deleted in the future @chat_id Chat identifier @parameters Parameters from "tg://statsrefresh?params=******" link @is_dark Pass true if a URL with the dark theme must be returned
//@description Returns an HTTP URL with the chat statistics. Currently this method of getting the statistics are disabled and can be deleted in the future @chat_id Chat identifier @parameters Parameters from "tg://statsrefresh?params=******" link @is_dark Pass true if a URL with the dark theme must be returned
getChatStatisticsUrl chat_id:int53 parameters:string is_dark:Bool = HttpUrl;
//@description Returns detailed statistics about a chat. Currently this method can be used only for supergroups and channels. Requires administrator rights in the channel @chat_id Chat identifier @is_dark Pass true if a dark theme is used by the app
//@description Returns detailed statistics about a chat. Currently this method can be used only for supergroups and channels. Can be used only if SupergroupFullInfo.can_get_statistics == true @chat_id Chat identifier @is_dark Pass true if a dark theme is used by the application
getChatStatistics chat_id:int53 is_dark:Bool = ChatStatistics;
//@description Loads asynchronous or zoomed in chat statistics graph @chat_id Chat identifier @token The token for graph loading @x X-value for zoomed in graph or 0 otherwise
getChatStatisticsGraph chat_id:int53 token:string x:int53 = StatisticsGraph;
//@description Returns detailed statistics about a message. Can be used only if Message.can_get_statistics == true @chat_id Chat identifier @message_id Message identifier @is_dark Pass true if a dark theme is used by the application
getMessageStatistics chat_id:int53 message_id:int53 is_dark:Bool = MessageStatistics;
//@description Loads asynchronous or zoomed in chat or message statistics graph @chat_id Chat identifier @token The token for graph loading @x X-value for zoomed in graph or 0 otherwise
getStatisticsGraph chat_id:int53 token:string x:int53 = StatisticsGraph;
//@description Returns storage usage statistics. Can be called before authorization @chat_limit The maximum number of chats with the largest storage usage for which separate statistics should be returned. All other chats will be grouped in entries with chat_id == 0. If the chat info database is not used, the chat_limit is ignored and is always set to 0
@ -4476,7 +4533,7 @@ getDatabaseStatistics = DatabaseStatistics;
//@file_types If not empty, only files with the given type(s) are considered. By default, all types except thumbnails, profile photos, stickers and wallpapers are deleted
//@chat_ids If not empty, only files from the given chats are considered. Use 0 as chat identifier to delete files not belonging to any chat (e.g., profile photos)
//@exclude_chat_ids If not empty, files from the given chats are excluded. Use 0 as chat identifier to exclude all files not belonging to any chat (e.g., profile photos)
//@return_deleted_file_statistics Pass true if deleted file statistics needs to be returned instead of the whole storage usage statistics. Affects only returned statistics
//@return_deleted_file_statistics Pass true if deleted file statistics need to be returned instead of the whole storage usage statistics. Affects only returned statistics
//@chat_limit Same as in getStorageStatistics. Affects only returned statistics
optimizeStorage size:int53 ttl:int32 count:int32 immunity_delay:int32 file_types:vector<FileType> chat_ids:vector<int53> exclude_chat_ids:vector<int53> return_deleted_file_statistics:Bool chat_limit:int32 = StorageStatistics;
@ -4590,7 +4647,7 @@ addStickerToSet user_id:int32 name:string sticker:InputSticker = StickerSet;
//@description Sets a sticker set thumbnail; for bots only. Returns the sticker set
//@user_id Sticker set owner @name Sticker set name
//@thumbnail Thumbnail to set in PNG or TGS format. Animated thumbnail must be set for animated sticker sets and only for them. You can use a zero InputFileId to delete the thumbnail
//@thumbnail Thumbnail to set in PNG or TGS format. Animated thumbnail must be set for animated sticker sets and only for them. Pass a zero InputFileId to delete the thumbnail
setStickerSetThumbnail user_id:int32 name:string thumbnail:InputFile = StickerSet;
//@description Changes the position of a sticker in the set to which it belongs; for bots only. The sticker set must have been created by the bot
@ -4620,9 +4677,15 @@ answerCustomQuery custom_query_id:int64 data:string = Ok;
setAlarm seconds:double = Ok;
//@description Returns information about existing countries. Can be called before authorization
getCountries = Countries;
//@description Uses current user IP address to find their country. Returns two-letter ISO 3166-1 alpha-2 country code. Can be called before authorization
getCountryCode = Text;
//@description Returns information about a phone number by its prefix. Can be called before authorization @phone_number_prefix The phone number prefix
getPhoneNumberInfo phone_number_prefix:string = PhoneNumberInfo;
//@description Returns the default text for invitation messages to be used as a placeholder when the current user invites friends to Telegram
getInviteText = Text;

Binary file not shown.

View File

@ -128,7 +128,7 @@ chatPhotoEmpty#37c1011c = ChatPhoto;
chatPhoto#d20b9f3c flags:# has_video:flags.0?true photo_small:FileLocation photo_big:FileLocation dc_id:int = ChatPhoto;
messageEmpty#83e5de54 id:int = Message;
message#452c0e65 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long restriction_reason:flags.22?Vector<RestrictionReason> = Message;
message#8a7e027d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int reply_to_top_id:flags.24?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long restriction_reason:flags.22?Vector<RestrictionReason> = Message;
messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message;
messageMediaEmpty#3ded6320 = MessageMedia;
@ -179,6 +179,7 @@ photoSizeEmpty#e17e23c type:string = PhotoSize;
photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;
photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize;
photoSizeProgressive#5aa86a51 type:string location:FileLocation w:int h:int sizes:Vector<int> = PhotoSize;
geoPointEmpty#1117dd5f = GeoPoint;
geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint;
@ -345,6 +346,8 @@ updateDialogFilterOrder#a5d72105 order:Vector<int> = Update;
updateDialogFilters#3504914f = Update;
updatePhoneCallSignalingData#2661bf09 phone_call_id:long data:bytes = Update;
updateChannelParticipant#65d2b464 flags:# channel_id:int date:int user_id:int prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant qts:int = Update;
updateChannelMessageForwards#6e8a84df channel_id:int id:int forwards:int = Update;
updateReadDiscussion#119fb587 peer:Peer msg_id:int read_max_id:int = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@ -534,7 +537,7 @@ botInfo#98e81d3a user_id:int description:string commands:Vector<BotCommand> = Bo
keyboardButton#a2fa4880 text:string = KeyboardButton;
keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton;
keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton;
keyboardButtonCallback#35bbdb6b flags:# requires_password:flags.0?true text:string data:bytes = KeyboardButton;
keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton;
keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton;
keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton;
@ -1137,6 +1140,23 @@ stats.megagroupStats#ef7ff916 period:StatsDateRangeDays members:StatsAbsValueAnd
globalPrivacySettings#bea2f424 flags:# archive_and_mute_new_noncontact_peers:flags.0?Bool = GlobalPrivacySettings;
help.countryCode#4203c5ef flags:# country_code:string prefixes:flags.0?Vector<string> patterns:flags.1?Vector<string> = help.CountryCode;
help.country#c3878e23 flags:# hidden:flags.0?true iso2:string default_name:string name:flags.1?string country_codes:Vector<help.CountryCode> = help.Country;
help.countriesListNotModified#93cc1f32 = help.CountriesList;
help.countriesList#87d0759e countries:Vector<help.Country> hash:int = help.CountriesList;
messageReplies#82e3c815 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector<int> channel_id:flags.0?int = MessageReplies;
messageViews#455b853d flags:# views:flags.0?int forwards:flags.1?int replies:flags.2?MessageReplies = MessageViews;
messages.messageViews#2c3f2ae2 views:Vector<MessageViews> users:Vector<User> = messages.MessageViews;
stats.messageStats#8999f295 views_graph:StatsGraph = stats.MessageStats;
messages.discussionMessage#d25fad90 message:Message read_max_id:int chats:Vector<Chat> users:Vector<User> = messages.DiscussionMessage;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@ -1261,7 +1281,7 @@ contacts.getLocated#d348bc44 flags:# background:flags.1?true geo_point:InputGeoP
messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages;
messages.getDialogs#a0ee3b73 flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs;
messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
messages.search#4e17810b flags:# peer:InputPeer q:string from_id:flags.0?InputUser top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int = messages.AffectedHistory;
messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
@ -1286,8 +1306,8 @@ messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerp
messages.discardEncryption#edd923c5 chat_id:int = Bool;
messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool;
messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool;
messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
messages.sendEncryptedFile#9a901b66 peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage;
messages.sendEncrypted#44fa7a15 flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
messages.sendEncryptedFile#5559481d flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage;
messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
messages.receivedQueue#55a5bb66 max_qts:int = Vector<long>;
messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool;
@ -1302,10 +1322,10 @@ messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet
messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult;
messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool;
messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates;
messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector<int> increment:Bool = Vector<int>;
messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector<int> increment:Bool = messages.MessageViews;
messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool;
messages.migrateChat#15a3b8e3 chat_id:int = Updates;
messages.searchGlobal#bf7225a4 flags:# folder_id:flags.0?int q:string offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
messages.searchGlobal#4bc6589a flags:# folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector<long> = Bool;
messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document;
messages.getSavedGifs#83bf3d52 hash:int = messages.SavedGifs;
@ -1316,7 +1336,7 @@ messages.sendInlineBotResult#220815b0 flags:# silent:flags.5?true background:fla
messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
messages.editMessage#48f71778 flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.15?int = Updates;
messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool;
messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer;
messages.getBotCallbackAnswer#9342ca07 flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes password:flags.2?InputCheckPasswordSRP = messages.BotCallbackAnswer;
messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool;
messages.getPeerDialogs#e470bcfd peers:Vector<InputDialogPeer> = messages.PeerDialogs;
messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector<MessageEntity> = Bool;
@ -1381,6 +1401,9 @@ messages.getSuggestedDialogFilters#a29cd42c = Vector<DialogFilterSuggested>;
messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool;
messages.updateDialogFiltersOrder#c563c1e4 order:Vector<int> = Bool;
messages.getOldFeaturedStickers#5fe7025b offset:int limit:int hash:int = messages.FeaturedStickers;
messages.getReplies#fda52fdc peer:InputPeer msg_id:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
messages.getDiscussionMessage#446972fd peer:InputPeer msg_id:int = messages.DiscussionMessage;
messages.readDiscussion#f731a9f4 peer:InputPeer msg_id:int read_max_id:int = Bool;
updates.getState#edd4882a = updates.State;
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
@ -1421,6 +1444,7 @@ help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector<Mess
help.getPromoData#c0977421 = help.PromoData;
help.hidePromoData#1e251c95 peer:InputPeer = Bool;
help.dismissSuggestion#77fa99f suggestion:string = Bool;
help.getCountriesList#735787a8 lang_code:string hash:int = help.CountriesList;
channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages;
@ -1498,3 +1522,5 @@ folders.deleteFolder#1c295881 folder_id:int = Updates;
stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats;
stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph;
stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel = stats.MegagroupStats;
stats.getMessagePublicForwards#5630281b channel:InputChannel msg_id:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats;

Binary file not shown.

View File

@ -824,6 +824,11 @@ void SessionConnection::send_ack(uint64 message_id) {
// an easiest way to eliminate duplicated acks for gzipped packets
if (to_ack_.empty() || to_ack_.back() != ack) {
to_ack_.push_back(ack);
constexpr size_t MAX_UNACKED_PACKETS = 100;
if (to_ack_.size() >= MAX_UNACKED_PACKETS) {
send_before(Time::now_cached());
}
}
}
@ -970,8 +975,8 @@ void SessionConnection::flush_packet() {
}
}
to_ack_.clear();
if (to_send_.empty()) {
if (to_send_.empty() && to_ack_.empty() && to_get_state_info_.empty() && to_resend_answer_.empty() &&
to_cancel_answer_.empty()) {
force_send_at_ = 0;
}
}

View File

@ -6,6 +6,8 @@
//
#pragma once
#include "td/utils/common.h"
namespace td {
enum class AccessRights : int32 { Read, Edit, Write };

View File

@ -277,6 +277,10 @@ void CallActor::rate_call(int32 rating, string comment, vector<td_api::object_pt
return "silent_remote";
case td_api::callProblemDropped::ID:
return "dropped";
case td_api::callProblemDistortedVideo::ID:
return "distorted_video";
case td_api::callProblemPixelatedVideo::ID:
return "pixelated_video";
default:
UNREACHABLE();
return "";

View File

@ -18,6 +18,7 @@
#include "td/telegram/Global.h"
#include "td/telegram/InlineQueriesManager.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/PasswordManager.h"
#include "td/telegram/Td.h"
#include "td/utils/common.h"
@ -38,7 +39,7 @@ class GetBotCallbackAnswerQuery : public Td::ResultHandler {
}
void send(DialogId dialog_id, MessageId message_id, const tl_object_ptr<td_api::CallbackQueryPayload> &payload,
int64 result_id) {
tl_object_ptr<telegram_api::InputCheckPasswordSRP> &&password, int64 result_id) {
result_id_ = result_id;
dialog_id_ = dialog_id;
message_id_ = message_id;
@ -56,6 +57,12 @@ class GetBotCallbackAnswerQuery : public Td::ResultHandler {
flags = telegram_api::messages_getBotCallbackAnswer::DATA_MASK;
data = BufferSlice(static_cast<const td_api::callbackQueryPayloadData *>(payload.get())->data_);
break;
case td_api::callbackQueryPayloadDataWithPassword::ID:
CHECK(password != nullptr);
flags = telegram_api::messages_getBotCallbackAnswer::DATA_MASK |
telegram_api::messages_getBotCallbackAnswer::PASSWORD_MASK;
data = BufferSlice(static_cast<const td_api::callbackQueryPayloadDataWithPassword *>(payload.get())->data_);
break;
case td_api::callbackQueryPayloadGame::ID:
flags = telegram_api::messages_getBotCallbackAnswer::GAME_MASK;
break;
@ -64,7 +71,8 @@ class GetBotCallbackAnswerQuery : public Td::ResultHandler {
}
auto net_query = G()->net_query_creator().create(telegram_api::messages_getBotCallbackAnswer(
flags, false /*ignored*/, std::move(input_peer), message_id.get_server_message_id().get(), std::move(data)));
flags, false /*ignored*/, std::move(input_peer), message_id.get_server_message_id().get(), std::move(data),
std::move(password)));
net_query->need_resend_on_503_ = false;
send_query(std::move(net_query));
}
@ -222,7 +230,7 @@ void CallbackQueriesManager::on_new_inline_query(
}
int64 CallbackQueriesManager::send_callback_query(FullMessageId full_message_id,
const tl_object_ptr<td_api::CallbackQueryPayload> &payload,
tl_object_ptr<td_api::CallbackQueryPayload> &&payload,
Promise<Unit> &&promise) {
if (td_->auth_manager_->is_bot()) {
promise.set_error(Status::Error(5, "Bot can't send callback queries to other bot"));
@ -260,12 +268,44 @@ int64 CallbackQueriesManager::send_callback_query(FullMessageId full_message_id,
} while (callback_query_answers_.find(result_id) != callback_query_answers_.end());
callback_query_answers_[result_id]; // reserve place for result
td_->create_handler<GetBotCallbackAnswerQuery>(std::move(promise))
->send(dialog_id, full_message_id.get_message_id(), payload, result_id);
if (payload->get_id() == td_api::callbackQueryPayloadDataWithPassword::ID) {
auto password = static_cast<const td_api::callbackQueryPayloadDataWithPassword *>(payload.get())->password_;
send_closure(td_->password_manager_, &PasswordManager::get_input_check_password_srp, std::move(password),
PromiseCreator::lambda(
[this, full_message_id, payload = std::move(payload), result_id, promise = std::move(promise)](
Result<tl_object_ptr<telegram_api::InputCheckPasswordSRP>> result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
send_get_callback_answer_query(full_message_id, std::move(payload), result.move_as_ok(),
result_id, std::move(promise));
}));
} else {
send_get_callback_answer_query(full_message_id, std::move(payload), nullptr, result_id, std::move(promise));
}
return result_id;
}
void CallbackQueriesManager::send_get_callback_answer_query(
FullMessageId full_message_id, tl_object_ptr<td_api::CallbackQueryPayload> &&payload,
tl_object_ptr<telegram_api::InputCheckPasswordSRP> &&password, int64 result_id, Promise<Unit> &&promise) {
auto dialog_id = full_message_id.get_dialog_id();
if (!td_->messages_manager_->have_input_peer(dialog_id, AccessRights::Read)) {
return promise.set_error(Status::Error(400, "Can't access the chat"));
}
if (!td_->messages_manager_->have_message_force(full_message_id, "send_callback_query")) {
return promise.set_error(Status::Error(5, "Message not found"));
}
td_->create_handler<GetBotCallbackAnswerQuery>(std::move(promise))
->send(dialog_id, full_message_id.get_message_id(), payload, std::move(password), result_id);
}
void CallbackQueriesManager::on_get_callback_query_answer(
int64 result_id, tl_object_ptr<telegram_api::messages_botCallbackAnswer> &&answer) {
LOG(INFO) << "Receive answer for callback query " << result_id;

View File

@ -39,7 +39,7 @@ class CallbackQueriesManager {
tl_object_ptr<telegram_api::inputBotInlineMessageID> &&inline_message_id, BufferSlice &&data,
int64 chat_instance, string &&game_short_name);
int64 send_callback_query(FullMessageId full_message_id, const tl_object_ptr<td_api::CallbackQueryPayload> &payload,
int64 send_callback_query(FullMessageId full_message_id, tl_object_ptr<td_api::CallbackQueryPayload> &&payload,
Promise<Unit> &&promise);
void on_get_callback_query_answer(int64 result_id, tl_object_ptr<telegram_api::messages_botCallbackAnswer> &&answer);
@ -60,6 +60,11 @@ class CallbackQueriesManager {
tl_object_ptr<td_api::CallbackQueryPayload> get_query_payload(int32 flags, BufferSlice &&data,
string &&game_short_name);
void send_get_callback_answer_query(FullMessageId full_message_id,
tl_object_ptr<td_api::CallbackQueryPayload> &&payload,
tl_object_ptr<telegram_api::InputCheckPasswordSRP> &&password, int64 result_id,
Promise<Unit> &&promise);
std::unordered_map<int64, CallbackQueryAnswer> callback_query_answers_;
Td *td_;

View File

@ -875,7 +875,7 @@ class ConfigRecoverer : public Actor {
};
ConfigManager::ConfigManager(ActorShared<> parent) : parent_(std::move(parent)) {
lazy_request_flood_countrol_.add_limit(20, 1);
lazy_request_flood_control_.add_limit(20, 1);
}
void ConfigManager::start_up() {
@ -930,7 +930,7 @@ void ConfigManager::request_config() {
return;
}
lazy_request_flood_countrol_.add_event(static_cast<int32>(Timestamp::now().at()));
lazy_request_flood_control_.add_event(static_cast<int32>(Timestamp::now().at()));
request_config_from_dc_impl(DcId::main());
}
@ -943,7 +943,7 @@ void ConfigManager::lazy_request_config() {
return;
}
expire_time_.relax(Timestamp::at(lazy_request_flood_countrol_.get_wakeup_at()));
expire_time_.relax(Timestamp::at(lazy_request_flood_control_.get_wakeup_at()));
set_timeout_at(expire_time_.at());
}

View File

@ -114,7 +114,7 @@ class ConfigManager : public NetQueryCallback {
int ref_cnt_{1};
Timestamp expire_time_;
FloodControlStrict lazy_request_flood_countrol_;
FloodControlStrict lazy_request_flood_control_;
vector<Promise<td_api::object_ptr<td_api::JsonValue>>> get_app_config_queries_;

View File

@ -2742,7 +2742,7 @@ tl_object_ptr<td_api::statisticsValue> ContactsManager::convert_stats_absolute_v
get_percentage_value(obj->current_ - obj->previous_, obj->previous_));
}
tl_object_ptr<td_api::ChatStatistics> ContactsManager::convert_megagroup_stats(
tl_object_ptr<td_api::chatStatisticsSupergroup> ContactsManager::convert_megagroup_stats(
tl_object_ptr<telegram_api::stats_megagroupStats> obj) {
CHECK(obj != nullptr);
@ -2785,7 +2785,7 @@ tl_object_ptr<td_api::ChatStatistics> ContactsManager::convert_megagroup_stats(
std::move(top_inviters));
}
tl_object_ptr<td_api::ChatStatistics> ContactsManager::convert_broadcast_stats(
tl_object_ptr<td_api::chatStatisticsChannel> ContactsManager::convert_broadcast_stats(
tl_object_ptr<telegram_api::stats_broadcastStats> obj) {
CHECK(obj != nullptr);
@ -2835,8 +2835,7 @@ class GetMegagroupStatsQuery : public Td::ResultHandler {
return on_error(id, result_ptr.move_as_error());
}
auto result = result_ptr.move_as_ok();
promise_.set_value(td->contacts_manager_->convert_megagroup_stats(std::move(result)));
promise_.set_value(td->contacts_manager_->convert_megagroup_stats(result_ptr.move_as_ok()));
}
void on_error(uint64 id, Status status) override {
@ -2874,8 +2873,13 @@ class GetBroadcastStatsQuery : public Td::ResultHandler {
return on_error(id, result_ptr.move_as_error());
}
auto result = result_ptr.move_as_ok();
promise_.set_value(ContactsManager::convert_broadcast_stats(std::move(result)));
auto result = ContactsManager::convert_broadcast_stats(result_ptr.move_as_ok());
for (auto &info : result->recent_message_interactions_) {
td->messages_manager_->on_update_message_interaction_info({DialogId(channel_id_), MessageId(info->message_id_)},
info->view_count_, info->forward_count_, false,
nullptr);
}
promise_.set_value(std::move(result));
}
void on_error(uint64 id, Status status) override {
@ -2884,6 +2888,51 @@ class GetBroadcastStatsQuery : public Td::ResultHandler {
}
};
tl_object_ptr<td_api::messageStatistics> ContactsManager::convert_message_stats(
tl_object_ptr<telegram_api::stats_messageStats> obj) {
return make_tl_object<td_api::messageStatistics>(convert_stats_graph(std::move(obj->views_graph_)));
}
class GetMessageStatsQuery : public Td::ResultHandler {
Promise<td_api::object_ptr<td_api::messageStatistics>> promise_;
ChannelId channel_id_;
public:
explicit GetMessageStatsQuery(Promise<td_api::object_ptr<td_api::messageStatistics>> &&promise)
: promise_(std::move(promise)) {
}
void send(ChannelId channel_id, MessageId message_id, bool is_dark, DcId dc_id) {
channel_id_ = channel_id;
auto input_channel = td->contacts_manager_->get_input_channel(channel_id);
CHECK(input_channel != nullptr);
int32 flags = 0;
if (is_dark) {
flags |= telegram_api::stats_getMessageStats::DARK_MASK;
}
send_query(G()->net_query_creator().create(
telegram_api::stats_getMessageStats(flags, false /*ignored*/, std::move(input_channel),
message_id.get_server_message_id().get()),
dc_id));
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::stats_getMessageStats>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
promise_.set_value(td->contacts_manager_->convert_message_stats(result_ptr.move_as_ok()));
}
void on_error(uint64 id, Status status) override {
td->contacts_manager_->on_get_channel_error(channel_id_, status, "GetMessageStatsQuery");
promise_.set_error(std::move(status));
}
};
class LoadAsyncGraphQuery : public Td::ResultHandler {
Promise<td_api::object_ptr<td_api::StatisticsGraph>> promise_;
@ -6068,6 +6117,56 @@ void ContactsManager::send_get_channel_stats_query(DcId dc_id, ChannelId channel
}
}
bool ContactsManager::can_get_channel_message_statistics(DialogId dialog_id) {
if (dialog_id.get_type() != DialogType::Channel) {
return false;
}
auto channel_id = dialog_id.get_channel_id();
const Channel *c = get_channel(channel_id);
if (c == nullptr || c->is_megagroup) {
return false;
}
auto channel_full = get_channel_full_force(channel_id, "can_get_channel_message_statistics");
if (channel_full == nullptr) {
return c->status.is_administrator();
}
return channel_full->stats_dc_id.is_exact();
}
void ContactsManager::get_channel_message_statistics(FullMessageId full_message_id, bool is_dark,
Promise<td_api::object_ptr<td_api::messageStatistics>> &&promise) {
auto dc_id_promise = PromiseCreator::lambda([actor_id = actor_id(this), full_message_id, is_dark,
promise = std::move(promise)](Result<DcId> r_dc_id) mutable {
if (r_dc_id.is_error()) {
return promise.set_error(r_dc_id.move_as_error());
}
send_closure(actor_id, &ContactsManager::send_get_channel_message_stats_query, r_dc_id.move_as_ok(),
full_message_id, is_dark, std::move(promise));
});
get_channel_statistics_dc_id(full_message_id.get_dialog_id(), false, std::move(dc_id_promise));
}
void ContactsManager::send_get_channel_message_stats_query(
DcId dc_id, FullMessageId full_message_id, bool is_dark,
Promise<td_api::object_ptr<td_api::messageStatistics>> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
auto dialog_id = full_message_id.get_dialog_id();
if (!td_->messages_manager_->have_message_force(full_message_id, "send_get_channel_message_stats_query")) {
return promise.set_error(Status::Error(400, "Message not found"));
}
if (!td_->messages_manager_->can_get_message_statistics(full_message_id)) {
return promise.set_error(Status::Error(400, "Message statistics is inaccessible"));
}
CHECK(dialog_id.get_type() == DialogType::Channel);
td_->create_handler<GetMessageStatsQuery>(std::move(promise))
->send(dialog_id.get_channel_id(), full_message_id.get_message_id(), is_dark, dc_id);
}
void ContactsManager::load_statistics_graph(DialogId dialog_id, const string &token, int64 x,
Promise<td_api::object_ptr<td_api::StatisticsGraph>> &&promise) {
auto dc_id_promise = PromiseCreator::lambda(
@ -12926,6 +13025,18 @@ bool ContactsManager::get_channel_sign_messages(const Channel *c) {
return c->sign_messages;
}
bool ContactsManager::get_channel_has_linked_channel(ChannelId channel_id) const {
auto c = get_channel(channel_id);
if (c == nullptr) {
return false;
}
return get_channel_has_linked_channel(c);
}
bool ContactsManager::get_channel_has_linked_channel(const Channel *c) {
return c->has_linked_channel;
}
int32 ContactsManager::get_channel_slow_mode_delay(ChannelId channel_id) {
auto channel_full = get_channel_full_force(channel_id, "get_channel_slow_mode_delay");
if (channel_full == nullptr) {

View File

@ -20,6 +20,7 @@
#include "td/telegram/files/FileId.h"
#include "td/telegram/files/FileSourceId.h"
#include "td/telegram/FolderId.h"
#include "td/telegram/FullMessageId.h"
#include "td/telegram/Location.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/net/DcId.h"
@ -376,6 +377,11 @@ class ContactsManager : public Actor {
void get_channel_statistics(DialogId dialog_id, bool is_dark,
Promise<td_api::object_ptr<td_api::ChatStatistics>> &&promise);
bool can_get_channel_message_statistics(DialogId dialog_id);
void get_channel_message_statistics(FullMessageId full_message_id, bool is_dark,
Promise<td_api::object_ptr<td_api::messageStatistics>> &&promise);
void load_statistics_graph(DialogId dialog_id, const string &token, int64 x,
Promise<td_api::object_ptr<td_api::StatisticsGraph>> &&promise);
@ -491,6 +497,7 @@ class ContactsManager : public Actor {
DialogParticipantStatus get_channel_permissions(ChannelId channel_id) const;
int32 get_channel_participant_count(ChannelId channel_id) const;
bool get_channel_sign_messages(ChannelId channel_id) const;
bool get_channel_has_linked_channel(ChannelId channel_id) const;
int32 get_channel_slow_mode_delay(ChannelId channel_id);
std::pair<int32, vector<UserId>> search_among_users(const vector<UserId> &user_ids, const string &query, int32 limit);
@ -581,11 +588,15 @@ class ContactsManager : public Actor {
static tl_object_ptr<td_api::statisticsValue> convert_stats_absolute_value(
const tl_object_ptr<telegram_api::statsAbsValueAndPrev> &obj);
tl_object_ptr<td_api::ChatStatistics> convert_megagroup_stats(tl_object_ptr<telegram_api::stats_megagroupStats> obj);
tl_object_ptr<td_api::chatStatisticsSupergroup> convert_megagroup_stats(
tl_object_ptr<telegram_api::stats_megagroupStats> obj);
static tl_object_ptr<td_api::ChatStatistics> convert_broadcast_stats(
static tl_object_ptr<td_api::chatStatisticsChannel> convert_broadcast_stats(
tl_object_ptr<telegram_api::stats_broadcastStats> obj);
static tl_object_ptr<td_api::messageStatistics> convert_message_stats(
tl_object_ptr<telegram_api::stats_messageStats> obj);
private:
struct User {
string first_name;
@ -1133,6 +1144,7 @@ class ContactsManager : public Actor {
static DialogParticipantStatus get_channel_status(const Channel *c);
DialogParticipantStatus get_channel_permissions(const Channel *c) const;
static bool get_channel_sign_messages(const Channel *c);
static bool get_channel_has_linked_channel(const Channel *c);
void set_my_id(UserId my_id);
@ -1444,6 +1456,9 @@ class ContactsManager : public Actor {
void send_get_channel_stats_query(DcId dc_id, ChannelId channel_id, bool is_dark,
Promise<td_api::object_ptr<td_api::ChatStatistics>> &&promise);
void send_get_channel_message_stats_query(DcId dc_id, FullMessageId full_message_id, bool is_dark,
Promise<td_api::object_ptr<td_api::messageStatistics>> &&promise);
void send_load_async_graph_query(DcId dc_id, string token, int64 x,
Promise<td_api::object_ptr<td_api::StatisticsGraph>> &&promise);

View File

@ -0,0 +1,372 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
//
// 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/CountryInfoManager.h"
#include "td/telegram/Global.h"
#include "td/telegram/LanguagePackManager.h"
#include "td/telegram/Td.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/buffer.h"
#include "td/utils/misc.h"
#include "td/utils/Random.h"
#include "td/utils/Status.h"
namespace td {
class GetNearestDcQuery : public Td::ResultHandler {
Promise<string> promise_;
public:
explicit GetNearestDcQuery(Promise<string> &&promise) : promise_(std::move(promise)) {
}
void send() {
send_query(G()->net_query_creator().create_unauth(telegram_api::help_getNearestDc()));
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::help_getNearestDc>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
auto result = result_ptr.move_as_ok();
promise_.set_value(std::move(result->country_));
}
void on_error(uint64 id, Status status) override {
if (!G()->is_expected_error(status) && status.message() != "BOT_METHOD_INVALID") {
LOG(ERROR) << "GetNearestDc returned " << status;
}
promise_.set_error(std::move(status));
}
};
class GetCountriesListQuery : public Td::ResultHandler {
Promise<tl_object_ptr<telegram_api::help_CountriesList>> promise_;
public:
explicit GetCountriesListQuery(Promise<tl_object_ptr<telegram_api::help_CountriesList>> &&promise)
: promise_(std::move(promise)) {
}
void send(const string &language_code, int32 hash) {
send_query(G()->net_query_creator().create_unauth(telegram_api::help_getCountriesList(language_code, hash)));
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::help_getCountriesList>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
promise_.set_value(result_ptr.move_as_ok());
}
void on_error(uint64 id, Status status) override {
if (!G()->is_expected_error(status)) {
LOG(ERROR) << "GetCountriesList returned " << status;
}
promise_.set_error(std::move(status));
}
};
struct CountryInfoManager::CallingCodeInfo {
string calling_code;
vector<string> prefixes;
vector<string> patterns;
};
struct CountryInfoManager::CountryInfo {
string country_code;
string default_name;
string name;
vector<CallingCodeInfo> calling_codes;
bool is_hidden = false;
td_api::object_ptr<td_api::countryInfo> get_country_info_object() const {
return td_api::make_object<td_api::countryInfo>(
country_code, name.empty() ? default_name : name, default_name, is_hidden,
transform(calling_codes, [](const CallingCodeInfo &info) { return info.calling_code; }));
}
};
struct CountryInfoManager::CountryList {
vector<CountryInfo> countries_;
int32 hash = 0;
double next_reload_time = 0.0;
td_api::object_ptr<td_api::countries> get_countries_object() const {
return td_api::make_object<td_api::countries>(
transform(countries_, [](const CountryInfo &info) { return info.get_country_info_object(); }));
}
};
CountryInfoManager::CountryInfoManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
}
void CountryInfoManager::tear_down() {
parent_.reset();
}
string CountryInfoManager::get_main_language_code() {
return to_lower(td_->language_pack_manager_->get_actor_unsafe()->get_main_language_code());
}
void CountryInfoManager::get_countries(Promise<td_api::object_ptr<td_api::countries>> &&promise) {
do_get_countries(get_main_language_code(), false, std::move(promise));
}
void CountryInfoManager::do_get_countries(string language_code, bool is_recursive,
Promise<td_api::object_ptr<td_api::countries>> &&promise) {
if (is_recursive) {
auto main_language_code = get_main_language_code();
if (language_code != main_language_code) {
language_code = std::move(main_language_code);
is_recursive = false;
}
}
auto list = get_country_list(language_code);
if (list == nullptr) {
if (is_recursive) {
return promise.set_error(Status::Error(500, "Requested data is inaccessible"));
}
return load_country_list(language_code, 0,
PromiseCreator::lambda([actor_id = actor_id(this), language_code,
promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
send_closure(actor_id, &CountryInfoManager::do_get_countries, std::move(language_code),
true, std::move(promise));
}));
}
promise.set_value(list->get_countries_object());
}
void CountryInfoManager::get_phone_number_info(string phone_number_prefix,
Promise<td_api::object_ptr<td_api::phoneNumberInfo>> &&promise) {
td::remove_if(phone_number_prefix, [](char c) { return c < '0' || c > '9'; });
if (phone_number_prefix.empty()) {
return promise.set_value(td_api::make_object<td_api::phoneNumberInfo>(nullptr, string(), string()));
}
do_get_phone_number_info(std::move(phone_number_prefix), get_main_language_code(), false, std::move(promise));
}
void CountryInfoManager::do_get_phone_number_info(string phone_number_prefix, string language_code, bool is_recursive,
Promise<td_api::object_ptr<td_api::phoneNumberInfo>> &&promise) {
if (is_recursive) {
auto main_language_code = get_main_language_code();
if (language_code != main_language_code) {
language_code = std::move(main_language_code);
is_recursive = false;
}
}
auto list = get_country_list(language_code);
if (list == nullptr) {
if (is_recursive) {
return promise.set_error(Status::Error(500, "Requested data is inaccessible"));
}
return load_country_list(language_code, 0,
PromiseCreator::lambda([actor_id = actor_id(this), phone_number_prefix, language_code,
promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
send_closure(actor_id, &CountryInfoManager::do_get_phone_number_info,
std::move(phone_number_prefix), std::move(language_code), true,
std::move(promise));
}));
}
Slice phone_number = phone_number_prefix;
const CountryInfo *best_country = nullptr;
const CallingCodeInfo *best_calling_code = nullptr;
size_t best_length = 0;
bool is_prefix = false;
for (auto &country : list->countries_) {
for (auto &calling_code : country.calling_codes) {
if (begins_with(phone_number, calling_code.calling_code)) {
auto calling_code_size = calling_code.calling_code.size();
for (auto &prefix : calling_code.prefixes) {
if (begins_with(prefix, phone_number.substr(calling_code_size))) {
is_prefix = true;
}
if (calling_code_size + prefix.size() > best_length &&
begins_with(phone_number.substr(calling_code_size), prefix)) {
best_country = &country;
best_calling_code = &calling_code;
best_length = calling_code_size + prefix.size();
}
}
}
if (begins_with(calling_code.calling_code, phone_number)) {
is_prefix = true;
}
}
}
if (best_country == nullptr) {
return promise.set_value(td_api::make_object<td_api::phoneNumberInfo>(
nullptr, is_prefix ? phone_number_prefix : string(), is_prefix ? string() : phone_number_prefix));
}
string formatted_part = phone_number_prefix.substr(best_calling_code->calling_code.size());
string formatted_phone_number = formatted_part;
size_t max_matched_digits = 0;
for (auto &pattern : best_calling_code->patterns) {
string result;
size_t current_pattern_pos = 0;
bool is_failed_match = false;
size_t matched_digits = 0;
for (auto &c : formatted_part) {
while (current_pattern_pos < pattern.size() && pattern[current_pattern_pos] != 'X' &&
!is_digit(pattern[current_pattern_pos])) {
result += pattern[current_pattern_pos++];
}
if (current_pattern_pos == pattern.size()) {
result += c;
} else if (pattern[current_pattern_pos] == 'X') {
result += c;
current_pattern_pos++;
} else {
CHECK(is_digit(pattern[current_pattern_pos]));
if (c == pattern[current_pattern_pos]) {
matched_digits++;
result += c;
current_pattern_pos++;
} else {
is_failed_match = true;
break;
}
}
}
if (!is_failed_match && matched_digits >= max_matched_digits) {
max_matched_digits = matched_digits;
formatted_phone_number = std::move(result);
}
}
promise.set_value(td_api::make_object<td_api::phoneNumberInfo>(
best_country->get_country_info_object(), best_calling_code->calling_code,
formatted_phone_number.empty() ? formatted_part : formatted_phone_number));
}
void CountryInfoManager::get_current_country_code(Promise<string> &&promise) {
td_->create_handler<GetNearestDcQuery>(std::move(promise))->send();
}
void CountryInfoManager::load_country_list(string language_code, int32 hash, Promise<Unit> &&promise) {
auto &queries = pending_load_country_queries_[language_code];
if (!promise && !queries.empty()) {
return;
}
queries.push_back(std::move(promise));
if (queries.size() == 1) {
auto query_promise = PromiseCreator::lambda(
[actor_id = actor_id(this), language_code](Result<tl_object_ptr<telegram_api::help_CountriesList>> &&result) {
send_closure(actor_id, &CountryInfoManager::on_get_country_list, language_code, std::move(result));
});
td_->create_handler<GetCountriesListQuery>(std::move(query_promise))->send(language_code, hash);
}
}
void CountryInfoManager::on_get_country_list(const string &language_code,
Result<tl_object_ptr<telegram_api::help_CountriesList>> r_country_list) {
auto query_it = pending_load_country_queries_.find(language_code);
CHECK(query_it != pending_load_country_queries_.end());
auto promises = std::move(query_it->second);
CHECK(!promises.empty());
pending_load_country_queries_.erase(query_it);
auto &countries = countries_[language_code];
if (r_country_list.is_error()) {
if (countries != nullptr) {
countries->next_reload_time = Time::now() + Random::fast(60, 120);
}
for (auto &promise : promises) {
promise.set_error(r_country_list.error().clone());
}
return;
}
auto country_list = r_country_list.move_as_ok();
CHECK(country_list != nullptr);
switch (country_list->get_id()) {
case telegram_api::help_countriesListNotModified::ID:
if (countries == nullptr) {
LOG(ERROR) << "Receive countriesListNotModified for unknown list with language code " << language_code;
countries_.erase(language_code);
} else {
LOG(INFO) << "List of countries with language code " << language_code << " is not modified";
countries->next_reload_time = Time::now() + Random::fast(86400, 2 * 86400);
}
break;
case telegram_api::help_countriesList::ID: {
auto list = move_tl_object_as<telegram_api::help_countriesList>(country_list);
if (countries == nullptr) {
countries = make_unique<CountryList>();
}
for (auto &c : list->countries_) {
CountryInfo info;
info.country_code = std::move(c->iso2_);
info.default_name = std::move(c->default_name_);
info.name = std::move(c->name_);
info.is_hidden = std::move(c->hidden_);
for (auto &code : c->country_codes_) {
auto r_calling_code = to_integer_safe<int32>(code->country_code_);
if (r_calling_code.is_error() || r_calling_code.ok() <= 0) {
LOG(ERROR) << "Receive invalid calling code " << code->country_code_ << " for country "
<< info.country_code;
} else {
CallingCodeInfo calling_code_info;
calling_code_info.calling_code = std::move(code->country_code_);
calling_code_info.prefixes = std::move(code->prefixes_);
if (calling_code_info.prefixes.empty()) {
calling_code_info.prefixes.resize(1);
}
calling_code_info.patterns = std::move(code->patterns_);
info.calling_codes.push_back(std::move(calling_code_info));
}
}
if (info.calling_codes.empty()) {
LOG(ERROR) << "Receive empty list of calling codes for " << info.country_code;
continue;
}
countries->countries_.push_back(std::move(info));
}
countries->hash = list->hash_;
countries->next_reload_time = Time::now() + Random::fast(86400, 2 * 86400);
break;
}
default:
UNREACHABLE();
}
for (auto &promise : promises) {
promise.set_value(Unit());
}
}
const CountryInfoManager::CountryList *CountryInfoManager::get_country_list(const string &language_code) {
auto it = countries_.find(language_code);
if (it == countries_.end()) {
return nullptr;
}
auto *country = it->second.get();
CHECK(country != nullptr);
if (country->next_reload_time < Time::now()) {
load_country_list(language_code, country->hash, Auto());
}
return country;
}
} // namespace td

View File

@ -0,0 +1,64 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
#include "td/utils/common.h"
#include "td/utils/Status.h"
#include <unordered_map>
namespace td {
class Td;
class CountryInfoManager : public Actor {
public:
explicit CountryInfoManager(Td *td, ActorShared<> parent);
void get_countries(Promise<td_api::object_ptr<td_api::countries>> &&promise);
void get_current_country_code(Promise<string> &&promise);
void get_phone_number_info(string phone_number_prefix,
Promise<td_api::object_ptr<td_api::phoneNumberInfo>> &&promise);
private:
void tear_down() override;
struct CallingCodeInfo;
struct CountryInfo;
struct CountryList;
string get_main_language_code();
void do_get_countries(string language_code, bool is_recursive,
Promise<td_api::object_ptr<td_api::countries>> &&promise);
void do_get_phone_number_info(string phone_number_prefix, string language_code, bool is_recursive,
Promise<td_api::object_ptr<td_api::phoneNumberInfo>> &&promise);
void load_country_list(string language_code, int32 hash, Promise<Unit> &&promise);
void on_get_country_list(const string &language_code,
Result<tl_object_ptr<telegram_api::help_CountriesList>> r_country_list);
const CountryList *get_country_list(const string &language_code);
std::unordered_map<string, vector<Promise<Unit>>> pending_load_country_queries_;
std::unordered_map<string, unique_ptr<CountryList>> countries_;
Td *td_;
ActorShared<> parent_;
};
} // namespace td

View File

@ -864,7 +864,8 @@ tl_object_ptr<td_api::minithumbnail> copy(const td_api::minithumbnail &obj) {
template <>
tl_object_ptr<td_api::photoSize> copy(const td_api::photoSize &obj) {
return make_tl_object<td_api::photoSize>(obj.type_, copy(obj.photo_), obj.width_, obj.height_);
return make_tl_object<td_api::photoSize>(obj.type_, copy(obj.photo_), obj.width_, obj.height_,
vector<int32>(obj.progressive_sizes_));
}
template <>

View File

@ -238,6 +238,50 @@ void LanguagePackManager::tear_down() {
}
}
string LanguagePackManager::get_main_language_code() {
if (language_pack_.empty() || language_code_.empty()) {
return "en";
}
if (language_code_.size() <= 2) {
return language_code_;
}
std::lock_guard<std::mutex> packs_lock(database_->mutex_);
auto pack_it = database_->language_packs_.find(language_pack_);
CHECK(pack_it != database_->language_packs_.end());
LanguageInfo *info = nullptr;
LanguagePack *pack = pack_it->second.get();
std::lock_guard<std::mutex> languages_lock(pack->mutex_);
if (is_custom_language_code(language_code_)) {
auto custom_it = pack->custom_language_pack_infos_.find(language_code_);
if (custom_it != pack->custom_language_pack_infos_.end()) {
info = &custom_it->second;
}
} else {
for (auto &server_info : pack->server_language_pack_infos_) {
if (server_info.first == language_code_) {
info = &server_info.second;
}
}
}
if (info == nullptr) {
LOG(ERROR) << "Failed to find information about chosen language " << language_code_;
if (!is_custom_language_code(language_code_)) {
search_language_info(language_code_, Auto());
}
} else {
if (!info->base_language_code_.empty()) {
return info->base_language_code_;
}
if (!info->plural_code_.empty()) {
return info->plural_code_;
}
}
return "en";
}
vector<string> LanguagePackManager::get_used_language_codes() {
if (language_pack_.empty() || language_code_.empty()) {
return {};

View File

@ -43,6 +43,8 @@ class LanguagePackManager : public NetQueryCallback {
static bool is_custom_language_code(Slice language_code);
string get_main_language_code();
vector<string> get_used_language_codes();
void on_language_pack_changed();

View File

@ -33,7 +33,7 @@
#include "td/telegram/MessageEntity.h"
#include "td/telegram/MessageEntity.hpp"
#include "td/telegram/MessageId.h"
#include "td/telegram/MessagesDb.h"
#include "td/telegram/MessageSearchFilter.h"
#include "td/telegram/misc.h"
#include "td/telegram/net/DcId.h"
#include "td/telegram/Payments.h"
@ -2447,7 +2447,7 @@ static int32 get_message_content_text_index_mask(const MessageContent *content)
for (auto &entity : text->entities) {
if (entity.type == MessageEntity::Type::Url || entity.type == MessageEntity::Type::EmailAddress ||
entity.type == MessageEntity::Type::TextUrl) {
return search_messages_filter_index_mask(SearchMessagesFilter::Url);
return message_search_filter_index_mask(MessageSearchFilter::Url);
}
}
return 0;
@ -2457,43 +2457,43 @@ static int32 get_message_content_media_index_mask(const MessageContent *content,
bool is_outgoing) {
switch (content->get_type()) {
case MessageContentType::Animation:
return search_messages_filter_index_mask(SearchMessagesFilter::Animation);
return message_search_filter_index_mask(MessageSearchFilter::Animation);
case MessageContentType::Audio: {
auto message_audio = static_cast<const MessageAudio *>(content);
auto duration = td->audios_manager_->get_audio_duration(message_audio->file_id);
return is_secret || duration > 0 ? search_messages_filter_index_mask(SearchMessagesFilter::Audio)
: search_messages_filter_index_mask(SearchMessagesFilter::Document);
return is_secret || duration > 0 ? message_search_filter_index_mask(MessageSearchFilter::Audio)
: message_search_filter_index_mask(MessageSearchFilter::Document);
}
case MessageContentType::Document:
return search_messages_filter_index_mask(SearchMessagesFilter::Document);
return message_search_filter_index_mask(MessageSearchFilter::Document);
case MessageContentType::Photo:
return search_messages_filter_index_mask(SearchMessagesFilter::Photo) |
search_messages_filter_index_mask(SearchMessagesFilter::PhotoAndVideo);
return message_search_filter_index_mask(MessageSearchFilter::Photo) |
message_search_filter_index_mask(MessageSearchFilter::PhotoAndVideo);
case MessageContentType::Video: {
auto message_video = static_cast<const MessageVideo *>(content);
auto duration = td->videos_manager_->get_video_duration(message_video->file_id);
return is_secret || duration > 0 ? search_messages_filter_index_mask(SearchMessagesFilter::Video) |
search_messages_filter_index_mask(SearchMessagesFilter::PhotoAndVideo)
: search_messages_filter_index_mask(SearchMessagesFilter::Document);
return is_secret || duration > 0 ? message_search_filter_index_mask(MessageSearchFilter::Video) |
message_search_filter_index_mask(MessageSearchFilter::PhotoAndVideo)
: message_search_filter_index_mask(MessageSearchFilter::Document);
}
case MessageContentType::VideoNote: {
auto message_video_note = static_cast<const MessageVideoNote *>(content);
auto duration = td->video_notes_manager_->get_video_note_duration(message_video_note->file_id);
return is_secret || duration > 0 ? search_messages_filter_index_mask(SearchMessagesFilter::VideoNote) |
search_messages_filter_index_mask(SearchMessagesFilter::VoiceAndVideoNote)
: search_messages_filter_index_mask(SearchMessagesFilter::Document);
return is_secret || duration > 0 ? message_search_filter_index_mask(MessageSearchFilter::VideoNote) |
message_search_filter_index_mask(MessageSearchFilter::VoiceAndVideoNote)
: message_search_filter_index_mask(MessageSearchFilter::Document);
}
case MessageContentType::VoiceNote:
return search_messages_filter_index_mask(SearchMessagesFilter::VoiceNote) |
search_messages_filter_index_mask(SearchMessagesFilter::VoiceAndVideoNote);
return message_search_filter_index_mask(MessageSearchFilter::VoiceNote) |
message_search_filter_index_mask(MessageSearchFilter::VoiceAndVideoNote);
case MessageContentType::ChatChangePhoto:
return search_messages_filter_index_mask(SearchMessagesFilter::ChatPhoto);
return message_search_filter_index_mask(MessageSearchFilter::ChatPhoto);
case MessageContentType::Call: {
int32 index_mask = search_messages_filter_index_mask(SearchMessagesFilter::Call);
int32 index_mask = message_search_filter_index_mask(MessageSearchFilter::Call);
auto message_call = static_cast<const MessageCall *>(content);
if (!is_outgoing && (message_call->discard_reason == CallDiscardReason::Declined ||
message_call->discard_reason == CallDiscardReason::Missed)) {
index_mask |= search_messages_filter_index_mask(SearchMessagesFilter::MissedCall);
index_mask |= message_search_filter_index_mask(MessageSearchFilter::MissedCall);
}
return index_mask;
}
@ -3355,17 +3355,17 @@ void unregister_message_content(Td *td, const MessageContent *content, FullMessa
template <class ToT, class FromT>
static tl_object_ptr<ToT> secret_to_telegram(FromT &from);
// fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation;
// fileLocationUnavailable volume_id:long local_id:int secret:long = FileLocation;
static auto secret_to_telegram(secret_api::fileLocationUnavailable &file_location) {
return make_tl_object<telegram_api::fileLocationToBeDeprecated>(file_location.volume_id_, file_location.local_id_);
}
// fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation;
// fileLocation dc_id:int volume_id:long local_id:int secret:long = FileLocation;
static auto secret_to_telegram(secret_api::fileLocation &file_location) {
return make_tl_object<telegram_api::fileLocationToBeDeprecated>(file_location.volume_id_, file_location.local_id_);
}
// photoSizeEmpty#e17e23c type:string = PhotoSize;
// photoSizeEmpty type:string = PhotoSize;
static auto secret_to_telegram(secret_api::photoSizeEmpty &empty) {
if (!clean_input_string(empty.type_)) {
empty.type_.clear();
@ -3373,7 +3373,7 @@ static auto secret_to_telegram(secret_api::photoSizeEmpty &empty) {
return make_tl_object<telegram_api::photoSizeEmpty>(empty.type_);
}
// photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
// photoSize type:string location:FileLocation w:int h:int size:int = PhotoSize;
static auto secret_to_telegram(secret_api::photoSize &photo_size) {
if (!clean_input_string(photo_size.type_)) {
photo_size.type_.clear();
@ -3383,7 +3383,7 @@ static auto secret_to_telegram(secret_api::photoSize &photo_size) {
photo_size.w_, photo_size.h_, photo_size.size_);
}
// photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;
// photoCachedSize type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;
static auto secret_to_telegram(secret_api::photoCachedSize &photo_size) {
if (!clean_input_string(photo_size.type_)) {
photo_size.type_.clear();
@ -3393,17 +3393,17 @@ static auto secret_to_telegram(secret_api::photoCachedSize &photo_size) {
photo_size.w_, photo_size.h_, photo_size.bytes_.clone());
}
// documentAttributeImageSize #6c37c15c w:int h:int = DocumentAttribute;
// documentAttributeImageSize w:int h:int = DocumentAttribute;
static auto secret_to_telegram(secret_api::documentAttributeImageSize &image_size) {
return make_tl_object<telegram_api::documentAttributeImageSize>(image_size.w_, image_size.h_);
}
// documentAttributeAnimated #11b58939 = DocumentAttribute;
// documentAttributeAnimated = DocumentAttribute;
static auto secret_to_telegram(secret_api::documentAttributeAnimated &animated) {
return make_tl_object<telegram_api::documentAttributeAnimated>();
}
// documentAttributeSticker23 #fb0a5727 = DocumentAttribute;
// documentAttributeSticker23 = DocumentAttribute;
static auto secret_to_telegram(secret_api::documentAttributeSticker23 &sticker) {
return make_tl_object<telegram_api::documentAttributeSticker>(
0, false /*ignored*/, "", make_tl_object<telegram_api::inputStickerSetEmpty>(), nullptr);
@ -3420,7 +3420,7 @@ static auto secret_to_telegram(secret_api::inputStickerSetShortName &sticker_set
return make_tl_object<telegram_api::inputStickerSetShortName>(sticker_set.short_name_);
}
// documentAttributeSticker #3a556302 alt:string stickerset:InputStickerSet = DocumentAttribute;
// documentAttributeSticker alt:string stickerset:InputStickerSet = DocumentAttribute;
static auto secret_to_telegram(secret_api::documentAttributeSticker &sticker) {
if (!clean_input_string(sticker.alt_)) {
sticker.alt_.clear();
@ -3430,13 +3430,13 @@ static auto secret_to_telegram(secret_api::documentAttributeSticker &sticker) {
nullptr);
}
// documentAttributeVideo #5910cccb duration:int w:int h:int = DocumentAttribute;
// documentAttributeVideo duration:int w:int h:int = DocumentAttribute;
static auto secret_to_telegram(secret_api::documentAttributeVideo &video) {
return make_tl_object<telegram_api::documentAttributeVideo>(0, false /*ignored*/, false /*ignored*/, video.duration_,
video.w_, video.h_);
}
// documentAttributeFilename #15590068 file_name:string = DocumentAttribute;
// documentAttributeFilename file_name:string = DocumentAttribute;
static auto secret_to_telegram(secret_api::documentAttributeFilename &filename) {
if (!clean_input_string(filename.file_name_)) {
filename.file_name_.clear();
@ -3444,7 +3444,7 @@ static auto secret_to_telegram(secret_api::documentAttributeFilename &filename)
return make_tl_object<telegram_api::documentAttributeFilename>(filename.file_name_);
}
// documentAttributeVideo66#ef02ce6 flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute;
// documentAttributeVideo66 flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute;
static auto secret_to_telegram(secret_api::documentAttributeVideo66 &video) {
return make_tl_object<telegram_api::documentAttributeVideo>(
(video.flags_ & secret_api::documentAttributeVideo66::ROUND_MESSAGE_MASK) != 0
@ -3479,16 +3479,16 @@ static auto telegram_documentAttributeAudio(bool is_voice_note, int duration, st
std::move(performer), std::move(waveform));
}
// documentAttributeAudio23 #51448e5 duration:int = DocumentAttribute;
// documentAttributeAudio23 duration:int = DocumentAttribute;
static auto secret_to_telegram(secret_api::documentAttributeAudio23 &audio) {
return telegram_documentAttributeAudio(false, audio.duration_, "", "", Auto());
}
// documentAttributeAudio45 #ded218e0 duration:int title:string performer:string = DocumentAttribute;
// documentAttributeAudio45 duration:int title:string performer:string = DocumentAttribute;
static auto secret_to_telegram(secret_api::documentAttributeAudio45 &audio) {
return telegram_documentAttributeAudio(false, audio.duration_, audio.title_, audio.performer_, Auto());
}
// documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string
// documentAttributeAudio flags:# voice:flags.10?true duration:int title:flags.0?string
// performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute;
static auto secret_to_telegram(secret_api::documentAttributeAudio &audio) {
return telegram_documentAttributeAudio((audio.flags_ & secret_api::documentAttributeAudio::VOICE_MASK) != 0,
@ -3506,7 +3506,7 @@ static auto secret_to_telegram(std::vector<tl_object_ptr<secret_api::DocumentAtt
return res;
}
// decryptedMessageMediaExternalDocument#fa95b0dd id:long access_hash:long date:int mime_type:string size:int
// decryptedMessageMediaExternalDocument id:long access_hash:long date:int mime_type:string size:int
// thumb:PhotoSize dc_id:int attributes:Vector<DocumentAttribute> = DecryptedMessageMedia;
static auto secret_to_telegram_document(secret_api::decryptedMessageMediaExternalDocument &from) {
if (!clean_input_string(from.mime_type_)) {
@ -3764,7 +3764,7 @@ unique_ptr<MessageContent> get_message_content(Td *td, FormattedText message,
tl_object_ptr<telegram_api::MessageMedia> &&media,
DialogId owner_dialog_id, bool is_content_read, UserId via_bot_user_id,
int32 *ttl) {
if (!td->auth_manager_->is_authorized() && !G()->close_flag() && media != nullptr) {
if (!td->auth_manager_->was_authorized() && !G()->close_flag() && media != nullptr) {
LOG(ERROR) << "Receive without authorization " << to_string(media);
media = nullptr;
}

View File

@ -26,6 +26,7 @@ namespace td {
int MessageEntity::get_type_priority(Type type) {
static const int types[] = {50, 50, 50, 50, 50, 90, 91, 20, 11, 10, 49, 49, 50, 50, 92, 93, 0, 50};
static_assert(sizeof(types) / sizeof(types[0]) == static_cast<size_t>(MessageEntity::Type::Size), "");
return types[static_cast<int32>(type)];
}

View File

@ -47,7 +47,8 @@ class MessageEntity {
Underline,
Strikethrough,
BlockQuote,
BankCardNumber
BankCardNumber,
Size
};
Type type;
int32 offset;

View File

@ -0,0 +1,56 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
//
// 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/MessageReplyInfo.h"
#include "td/utils/logging.h"
namespace td {
MessageReplyInfo::MessageReplyInfo(tl_object_ptr<telegram_api::messageReplies> &&reply_info, bool is_bot) {
if (reply_info == nullptr) {
return;
}
if (reply_info->replies_ < 0) {
LOG(ERROR) << "Receive wrong " << to_string(reply_info);
return;
}
reply_count = reply_info->replies_;
pts = reply_info->replies_pts_;
if (!is_bot) {
for (auto &user_id_int : reply_info->recent_repliers_) {
UserId user_id(user_id_int);
if (user_id.is_valid()) {
recent_replier_user_ids.push_back(user_id);
} else {
LOG(ERROR) << "Receive " << user_id << " as a recent replier";
}
}
}
is_comment = reply_info->comments_;
if (is_comment) {
channel_id = ChannelId(reply_info->channel_id_);
if (!channel_id.is_valid()) {
LOG(ERROR) << "Receive invalid " << channel_id;
channel_id = ChannelId();
}
}
}
bool MessageReplyInfo::need_update_to(const MessageReplyInfo &other) const {
if (other.pts < pts) {
return false;
}
return true;
}
StringBuilder &operator<<(StringBuilder &string_builder, const MessageReplyInfo &reply_info) {
return string_builder << reply_info.reply_count << " replies by " << reply_info.recent_replier_user_ids;
}
} // namespace td

View File

@ -0,0 +1,79 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
//
// 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/ChannelId.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/UserId.h"
#include "td/utils/common.h"
#include "td/utils/StringBuilder.h"
#include "td/utils/tl_helpers.h"
namespace td {
struct MessageReplyInfo {
int32 reply_count = -1;
int32 pts = -1;
vector<UserId> recent_replier_user_ids;
ChannelId channel_id;
bool is_comment = false;
MessageReplyInfo() = default;
MessageReplyInfo(tl_object_ptr<telegram_api::messageReplies> &&reply_info, bool is_bot);
bool is_empty() const {
return reply_count < 0;
}
bool need_update_to(const MessageReplyInfo &other) const;
template <class StorerT>
void store(StorerT &storer) const {
CHECK(!is_empty());
bool has_recent_replier_user_ids = !recent_replier_user_ids.empty();
bool has_channel_id = channel_id.is_valid();
BEGIN_STORE_FLAGS();
STORE_FLAG(is_comment);
STORE_FLAG(has_recent_replier_user_ids);
STORE_FLAG(has_channel_id);
END_STORE_FLAGS();
td::store(reply_count, storer);
td::store(pts, storer);
if (has_recent_replier_user_ids) {
td::store(recent_replier_user_ids, storer);
}
if (has_channel_id) {
td::store(channel_id, storer);
}
}
template <class ParserT>
void parse(ParserT &parser) {
CHECK(!is_empty());
bool has_recent_replier_user_ids = !recent_replier_user_ids.empty();
bool has_channel_id = channel_id.is_valid();
BEGIN_PARSE_FLAGS();
PARSE_FLAG(is_comment);
PARSE_FLAG(has_recent_replier_user_ids);
PARSE_FLAG(has_channel_id);
END_PARSE_FLAGS();
td::parse(reply_count, parser);
td::parse(pts, parser);
if (has_recent_replier_user_ids) {
td::parse(recent_replier_user_ids, parser);
}
if (has_channel_id) {
td::parse(channel_id, parser);
}
}
};
StringBuilder &operator<<(StringBuilder &string_builder, const MessageReplyInfo &reply_info);
} // namespace td

View File

@ -0,0 +1,141 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
//
// 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/MessageSearchFilter.h"
#include "td/utils/common.h"
namespace td {
tl_object_ptr<telegram_api::MessagesFilter> get_input_messages_filter(MessageSearchFilter filter) {
switch (filter) {
case MessageSearchFilter::Empty:
return make_tl_object<telegram_api::inputMessagesFilterEmpty>();
case MessageSearchFilter::Animation:
return make_tl_object<telegram_api::inputMessagesFilterGif>();
case MessageSearchFilter::Audio:
return make_tl_object<telegram_api::inputMessagesFilterMusic>();
case MessageSearchFilter::Document:
return make_tl_object<telegram_api::inputMessagesFilterDocument>();
case MessageSearchFilter::Photo:
return make_tl_object<telegram_api::inputMessagesFilterPhotos>();
case MessageSearchFilter::Video:
return make_tl_object<telegram_api::inputMessagesFilterVideo>();
case MessageSearchFilter::VoiceNote:
return make_tl_object<telegram_api::inputMessagesFilterVoice>();
case MessageSearchFilter::PhotoAndVideo:
return make_tl_object<telegram_api::inputMessagesFilterPhotoVideo>();
case MessageSearchFilter::Url:
return make_tl_object<telegram_api::inputMessagesFilterUrl>();
case MessageSearchFilter::ChatPhoto:
return make_tl_object<telegram_api::inputMessagesFilterChatPhotos>();
case MessageSearchFilter::Call:
return make_tl_object<telegram_api::inputMessagesFilterPhoneCalls>(0, false /*ignored*/);
case MessageSearchFilter::MissedCall:
return make_tl_object<telegram_api::inputMessagesFilterPhoneCalls>(
telegram_api::inputMessagesFilterPhoneCalls::MISSED_MASK, false /*ignored*/);
case MessageSearchFilter::VideoNote:
return make_tl_object<telegram_api::inputMessagesFilterRoundVideo>();
case MessageSearchFilter::VoiceAndVideoNote:
return make_tl_object<telegram_api::inputMessagesFilterRoundVoice>();
case MessageSearchFilter::Mention:
return make_tl_object<telegram_api::inputMessagesFilterMyMentions>();
case MessageSearchFilter::UnreadMention:
case MessageSearchFilter::FailedToSend:
default:
UNREACHABLE();
return nullptr;
}
}
MessageSearchFilter get_message_search_filter(const tl_object_ptr<td_api::SearchMessagesFilter> &filter) {
if (filter == nullptr) {
return MessageSearchFilter::Empty;
}
switch (filter->get_id()) {
case td_api::searchMessagesFilterEmpty::ID:
return MessageSearchFilter::Empty;
case td_api::searchMessagesFilterAnimation::ID:
return MessageSearchFilter::Animation;
case td_api::searchMessagesFilterAudio::ID:
return MessageSearchFilter::Audio;
case td_api::searchMessagesFilterDocument::ID:
return MessageSearchFilter::Document;
case td_api::searchMessagesFilterPhoto::ID:
return MessageSearchFilter::Photo;
case td_api::searchMessagesFilterVideo::ID:
return MessageSearchFilter::Video;
case td_api::searchMessagesFilterVoiceNote::ID:
return MessageSearchFilter::VoiceNote;
case td_api::searchMessagesFilterPhotoAndVideo::ID:
return MessageSearchFilter::PhotoAndVideo;
case td_api::searchMessagesFilterUrl::ID:
return MessageSearchFilter::Url;
case td_api::searchMessagesFilterChatPhoto::ID:
return MessageSearchFilter::ChatPhoto;
case td_api::searchMessagesFilterCall::ID:
return MessageSearchFilter::Call;
case td_api::searchMessagesFilterMissedCall::ID:
return MessageSearchFilter::MissedCall;
case td_api::searchMessagesFilterVideoNote::ID:
return MessageSearchFilter::VideoNote;
case td_api::searchMessagesFilterVoiceAndVideoNote::ID:
return MessageSearchFilter::VoiceAndVideoNote;
case td_api::searchMessagesFilterMention::ID:
return MessageSearchFilter::Mention;
case td_api::searchMessagesFilterUnreadMention::ID:
return MessageSearchFilter::UnreadMention;
case td_api::searchMessagesFilterFailedToSend::ID:
return MessageSearchFilter::FailedToSend;
default:
UNREACHABLE();
return MessageSearchFilter::Empty;
}
}
StringBuilder &operator<<(StringBuilder &string_builder, MessageSearchFilter filter) {
switch (filter) {
case MessageSearchFilter::Empty:
return string_builder << "Empty";
case MessageSearchFilter::Animation:
return string_builder << "Animation";
case MessageSearchFilter::Audio:
return string_builder << "Audio";
case MessageSearchFilter::Document:
return string_builder << "Document";
case MessageSearchFilter::Photo:
return string_builder << "Photo";
case MessageSearchFilter::Video:
return string_builder << "Video";
case MessageSearchFilter::VoiceNote:
return string_builder << "VoiceNote";
case MessageSearchFilter::PhotoAndVideo:
return string_builder << "PhotoAndVideo";
case MessageSearchFilter::Url:
return string_builder << "Url";
case MessageSearchFilter::ChatPhoto:
return string_builder << "ChatPhoto";
case MessageSearchFilter::Call:
return string_builder << "Call";
case MessageSearchFilter::MissedCall:
return string_builder << "MissedCall";
case MessageSearchFilter::VideoNote:
return string_builder << "VideoNote";
case MessageSearchFilter::VoiceAndVideoNote:
return string_builder << "VoiceAndVideoNote";
case MessageSearchFilter::Mention:
return string_builder << "Mention";
case MessageSearchFilter::UnreadMention:
return string_builder << "UnreadMention";
case MessageSearchFilter::FailedToSend:
return string_builder << "FailedToSend";
default:
UNREACHABLE();
return string_builder;
}
}
} // namespace td

View File

@ -0,0 +1,66 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/common.h"
#include "td/utils/StringBuilder.h"
namespace td {
// append only before Size
enum class MessageSearchFilter : int32 {
Empty,
Animation,
Audio,
Document,
Photo,
Video,
VoiceNote,
PhotoAndVideo,
Url,
ChatPhoto,
Call,
MissedCall,
VideoNote,
VoiceAndVideoNote,
Mention,
UnreadMention,
FailedToSend,
Size
};
inline constexpr size_t message_search_filter_count() {
return static_cast<int32>(MessageSearchFilter::Size) - 1;
}
inline int32 message_search_filter_index(MessageSearchFilter filter) {
CHECK(filter != MessageSearchFilter::Empty);
return static_cast<int32>(filter) - 1;
}
inline int32 message_search_filter_index_mask(MessageSearchFilter filter) {
if (filter == MessageSearchFilter::Empty) {
return 0;
}
return 1 << message_search_filter_index(filter);
}
inline int32 call_message_search_filter_index(MessageSearchFilter filter) {
CHECK(filter == MessageSearchFilter::Call || filter == MessageSearchFilter::MissedCall);
return static_cast<int32>(filter) - static_cast<int32>(MessageSearchFilter::Call);
}
tl_object_ptr<telegram_api::MessagesFilter> get_input_messages_filter(MessageSearchFilter filter);
MessageSearchFilter get_message_search_filter(const tl_object_ptr<td_api::SearchMessagesFilter> &filter);
StringBuilder &operator<<(StringBuilder &string_builder, MessageSearchFilter filter);
} // namespace td

View File

@ -7,6 +7,7 @@
#include "td/telegram/MessagesDb.h"
#include "td/telegram/logevent/LogEvent.h"
#include "td/telegram/MessageSearchFilter.h"
#include "td/telegram/Version.h"
#include "td/db/SqliteConnectionSafe.h"
@ -85,12 +86,12 @@ Status init_messages_db(SqliteDb &db, int32 version) {
return Status::OK();
};
auto add_call_index = [&db]() {
// for (int i = static_cast<int>(SearchMessagesFilter::Call) - 1;
// i < static_cast<int>(SearchMessagesFilter::MissedCall); i++) {
// TRY_STATUS(db.exec(PSLICE() << "CREATE INDEX IF NOT EXISTS full_message_index_" << i
// << " ON messages (unique_message_id) WHERE (index_mask & " << (1 << i) << ") != 0"));
// }
auto add_call_index = [&db] {
// for (int i = static_cast<int>(MessageSearchFilter::Call) - 1; i < static_cast<int>(MessageSearchFilter::MissedCall);
// i++) {
// TRY_STATUS(db.exec(PSLICE() << "CREATE INDEX IF NOT EXISTS full_message_index_" << i
// << " ON messages (unique_message_id) WHERE (index_mask & " << (1 << i) << ") != 0"));
// }
return Status::OK();
};
auto add_notification_id_index = [&db] {
@ -241,8 +242,8 @@ class MessagesDbImpl : public MessagesDbSyncInterface {
// LOG(ERROR) << get_messages_from_index_stmts_[i].asc_stmt_.explain().ok();
}
for (int i = static_cast<int>(SearchMessagesFilter::Call) - 1, pos = 0;
i < static_cast<int>(SearchMessagesFilter::MissedCall); i++, pos++) {
for (int i = static_cast<int>(MessageSearchFilter::Call) - 1, pos = 0;
i < static_cast<int>(MessageSearchFilter::MissedCall); i++, pos++) {
TRY_RESULT_ASSIGN(
get_calls_stmts_[pos],
db_memory_.get_statement(
@ -765,12 +766,12 @@ class MessagesDbImpl : public MessagesDbSyncInterface {
return Status::Error("Union is not supported");
}
int32 pos;
if (index_i + 1 == static_cast<int>(SearchMessagesFilter::Call)) {
if (index_i + 1 == static_cast<int>(MessageSearchFilter::Call)) {
pos = 0;
} else if (index_i + 1 == static_cast<int>(SearchMessagesFilter::MissedCall)) {
} else if (index_i + 1 == static_cast<int>(MessageSearchFilter::MissedCall)) {
pos = 1;
} else {
return Status::Error(PSLICE() << "Index_mask is not Call or MissedCall " << query.index_mask);
return Status::Error(PSLICE() << "Index mask is not Call or MissedCall " << query.index_mask);
}
auto &stmt = get_calls_stmts_[pos];

View File

@ -26,28 +26,6 @@ namespace td {
class SqliteConnectionSafe;
class SqliteDb;
// append only before Size
enum class SearchMessagesFilter : int32 {
Empty,
Animation,
Audio,
Document,
Photo,
Video,
VoiceNote,
PhotoAndVideo,
Url,
ChatPhoto,
Call,
MissedCall,
VideoNote,
VoiceAndVideoNote,
Mention,
UnreadMention,
FailedToSend,
Size
};
struct MessagesDbMessagesQuery {
DialogId dialog_id;
int32 index_mask{0};
@ -178,25 +156,4 @@ std::shared_ptr<MessagesDbSyncSafeInterface> create_messages_db_sync(
std::shared_ptr<MessagesDbAsyncInterface> create_messages_db_async(std::shared_ptr<MessagesDbSyncSafeInterface> sync_db,
int32 scheduler_id);
inline constexpr size_t search_messages_filter_size() {
return static_cast<int32>(SearchMessagesFilter::Size) - 1;
}
inline int32 search_messages_filter_index(SearchMessagesFilter filter) {
CHECK(filter != SearchMessagesFilter::Empty);
return static_cast<int32>(filter) - 1;
}
inline int32 search_messages_filter_index_mask(SearchMessagesFilter filter) {
if (filter == SearchMessagesFilter::Empty) {
return 0;
}
return 1 << search_messages_filter_index(filter);
}
inline int32 search_calls_filter_index(SearchMessagesFilter filter) {
CHECK(filter == SearchMessagesFilter::Call || filter == SearchMessagesFilter::MissedCall);
return static_cast<int32>(filter) - static_cast<int32>(SearchMessagesFilter::Call);
}
} // namespace td

File diff suppressed because it is too large Load Diff

View File

@ -6,10 +6,6 @@
//
#pragma once
#include "td/telegram/secret_api.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/AccessRights.h"
#include "td/telegram/ChannelId.h"
#include "td/telegram/Dependencies.h"
@ -31,7 +27,9 @@
#include "td/telegram/MessageContentType.h"
#include "td/telegram/MessageCopyOptions.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/MessageReplyInfo.h"
#include "td/telegram/MessagesDb.h"
#include "td/telegram/MessageSearchFilter.h"
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/Notification.h"
#include "td/telegram/NotificationGroupId.h"
@ -47,6 +45,10 @@
#include "td/telegram/ServerMessageId.h"
#include "td/telegram/UserId.h"
#include "td/telegram/secret_api.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/actor/actor.h"
#include "td/actor/MultiPromise.h"
#include "td/actor/PromiseFuture.h"
@ -151,7 +153,7 @@ class MessagesManager : public Actor {
static constexpr int32 MESSAGE_FLAG_HAS_ENTITIES = 1 << 7;
static constexpr int32 MESSAGE_FLAG_HAS_FROM_ID = 1 << 8;
static constexpr int32 MESSAGE_FLAG_HAS_MEDIA = 1 << 9;
static constexpr int32 MESSAGE_FLAG_HAS_VIEWS = 1 << 10;
static constexpr int32 MESSAGE_FLAG_HAS_INTERACTION_INFO = 1 << 10;
static constexpr int32 MESSAGE_FLAG_IS_SENT_VIA_BOT = 1 << 11;
static constexpr int32 MESSAGE_FLAG_IS_SILENT = 1 << 13;
static constexpr int32 MESSAGE_FLAG_IS_POST = 1 << 14;
@ -162,6 +164,8 @@ class MessagesManager : public Actor {
static constexpr int32 MESSAGE_FLAG_IS_LEGACY = 1 << 19;
static constexpr int32 MESSAGE_FLAG_HIDE_EDIT_DATE = 1 << 21;
static constexpr int32 MESSAGE_FLAG_IS_RESTRICTED = 1 << 22;
static constexpr int32 MESSAGE_FLAG_HAS_REPLY_INFO = 1 << 23;
static constexpr int32 MESSAGE_FLAG_HAS_RECENT_REPLIERS = 1 << 24;
static constexpr int32 SEND_MESSAGE_FLAG_IS_REPLY = 1 << 0;
static constexpr int32 SEND_MESSAGE_FLAG_DISABLE_WEB_PAGE_PREVIEW = 1 << 1;
@ -230,12 +234,13 @@ class MessagesManager : public Actor {
void on_get_dialog_messages_search_result(DialogId dialog_id, const string &query, UserId sender_user_id,
MessageId from_message_id, int32 offset, int32 limit,
SearchMessagesFilter filter, int64 random_id, int32 total_count,
MessageSearchFilter filter, int64 random_id, int32 total_count,
vector<tl_object_ptr<telegram_api::Message>> &&messages);
void on_failed_dialog_messages_search(DialogId dialog_id, int64 random_id);
void on_get_messages_search_result(const string &query, int32 offset_date, DialogId offset_dialog_id,
MessageId offset_message_id, int32 limit, int64 random_id, int32 total_count,
MessageId offset_message_id, int32 limit, MessageSearchFilter filter,
int64 random_id, int32 total_count,
vector<tl_object_ptr<telegram_api::Message>> &&messages);
void on_failed_messages_search(int64 random_id);
@ -246,6 +251,10 @@ class MessagesManager : public Actor {
vector<tl_object_ptr<telegram_api::Message>> &&messages);
void on_get_recent_locations_failed(int64 random_id);
void on_get_message_public_forwards_result(int64 random_id, int32 total_count,
vector<tl_object_ptr<telegram_api::Message>> &&messages);
void on_failed_get_message_public_forwards(int64 random_id);
// if message is from_update, flags have_previous and have_next are ignored and should be both true
FullMessageId on_get_message(tl_object_ptr<telegram_api::Message> message_ptr, bool from_update,
bool is_channel_message, bool is_scheduled, bool have_previous, bool have_next,
@ -323,7 +332,13 @@ class MessagesManager : public Actor {
void on_update_channel_too_long(tl_object_ptr<telegram_api::updateChannelTooLong> &&update, bool force_apply);
void on_update_message_views(FullMessageId full_message_id, int32 views);
void on_update_message_view_count(FullMessageId full_message_id, int32 view_count);
void on_update_message_forward_count(FullMessageId full_message_id, int32 forward_count);
void on_update_message_interaction_info(FullMessageId full_message_id, int32 view_count, int32 forward_count,
bool has_reply_info,
tl_object_ptr<telegram_api::messageReplies> &&reply_info);
void on_update_live_location_viewed(FullMessageId full_message_id);
@ -528,6 +543,8 @@ class MessagesManager : public Actor {
vector<DialogId> get_common_dialogs(UserId user_id, DialogId offset_dialog_id, int32 limit, bool force,
Promise<Unit> &&promise);
bool can_get_message_statistics(FullMessageId full_message_id);
bool have_message_force(FullMessageId full_message_id, const char *source);
void get_message(FullMessageId full_message_id, Promise<Unit> &&promise);
@ -643,18 +660,25 @@ class MessagesManager : public Actor {
std::pair<int32, vector<MessageId>> search_dialog_messages(DialogId dialog_id, const string &query,
UserId sender_user_id, MessageId from_message_id,
int32 offset, int32 limit,
const tl_object_ptr<td_api::SearchMessagesFilter> &filter,
int32 offset, int32 limit, MessageSearchFilter filter,
int64 &random_id, bool use_db, Promise<Unit> &&promise);
std::pair<int64, vector<FullMessageId>> offline_search_messages(
DialogId dialog_id, const string &query, int64 from_search_id, int32 limit,
const tl_object_ptr<td_api::SearchMessagesFilter> &filter, int64 &random_id, Promise<> &&promise);
struct FoundMessages {
vector<FullMessageId> full_message_ids;
string next_offset;
int32 total_count = 0;
};
td_api::object_ptr<td_api::foundMessages> get_found_messages_object(const FoundMessages &found_messages);
FoundMessages offline_search_messages(DialogId dialog_id, const string &query, const string &offset, int32 limit,
MessageSearchFilter filter, int64 &random_id, Promise<> &&promise);
std::pair<int32, vector<FullMessageId>> search_messages(FolderId folder_id, bool ignore_folder_id,
const string &query, int32 offset_date,
DialogId offset_dialog_id, MessageId offset_message_id,
int32 limit, int64 &random_id, Promise<Unit> &&promise);
int32 limit, MessageSearchFilter filter, int64 &random_id,
Promise<Unit> &&promise);
std::pair<int32, vector<FullMessageId>> search_call_messages(MessageId from_message_id, int32 limit, bool only_missed,
int64 &random_id, bool use_db, Promise<Unit> &&promise);
@ -671,12 +695,15 @@ class MessagesManager : public Actor {
void on_get_dialog_message_by_date_fail(int64 random_id);
int32 get_dialog_message_count(DialogId dialog_id, const tl_object_ptr<td_api::SearchMessagesFilter> &filter,
bool return_local, int64 &random_id, Promise<Unit> &&promise);
int32 get_dialog_message_count(DialogId dialog_id, MessageSearchFilter filter, bool return_local, int64 &random_id,
Promise<Unit> &&promise);
vector<MessageId> get_dialog_scheduled_messages(DialogId dialog_id, bool force, bool ignore_result,
Promise<Unit> &&promise);
FoundMessages get_message_public_forwards(FullMessageId full_message_id, const string &offset, int32 limit,
int64 &random_id, Promise<Unit> &&promise);
tl_object_ptr<td_api::message> get_dialog_message_by_date_object(int64 random_id);
tl_object_ptr<td_api::message> get_message_object(FullMessageId full_message_id);
@ -710,10 +737,6 @@ class MessagesManager : public Actor {
void on_resolved_username(const string &username, DialogId dialog_id);
void drop_username(const string &username);
static tl_object_ptr<telegram_api::MessagesFilter> get_input_messages_filter(SearchMessagesFilter filter);
static SearchMessagesFilter get_search_messages_filter(const tl_object_ptr<td_api::SearchMessagesFilter> &filter);
tl_object_ptr<telegram_api::InputNotifyPeer> get_input_notify_peer(DialogId dialogId) const;
void on_update_dialog_notify_settings(DialogId dialog_id,
@ -887,7 +910,9 @@ class MessagesManager : public Actor {
tl_object_ptr<telegram_api::messageFwdHeader> forward_header;
MessageId reply_to_message_id;
UserId via_bot_user_id;
int32 views = 0;
int32 view_count = 0;
int32 forward_count = 0;
tl_object_ptr<telegram_api::messageReplies> reply_info;
int32 flags = 0;
int32 edit_date = 0;
vector<RestrictionReason> restriction_reasons;
@ -999,7 +1024,10 @@ class MessagesManager : public Actor {
NotificationId notification_id;
NotificationId removed_notification_id;
int32 views = 0;
int32 view_count = 0;
int32 forward_count = 0;
MessageReplyInfo reply_info;
int32 legacy_layer = 0;
int32 send_error_code = 0;
@ -1065,9 +1093,9 @@ class MessagesManager : public Actor {
// is known and last_message_id is known, then last_database_message_id <=
// last_message_id
std::array<MessageId, search_messages_filter_size()> first_database_message_id_by_index;
std::array<MessageId, message_search_filter_count()> first_database_message_id_by_index;
// use struct Count?
std::array<int32, search_messages_filter_size()> message_count_by_index{{0}};
std::array<int32, message_search_filter_count()> message_count_by_index{{0}};
int32 server_unread_count = 0;
int32 local_unread_count = 0;
@ -1759,6 +1787,8 @@ class MessagesManager : public Actor {
static bool can_forward_message(DialogId from_dialog_id, const Message *m);
bool can_get_message_statistics(DialogId dialog_id, const Message *m) const;
static bool can_delete_channel_message(DialogParticipantStatus status, const Message *m, bool is_bot);
bool can_delete_message(DialogId dialog_id, const Message *m) const;
@ -1820,7 +1850,14 @@ class MessagesManager : public Actor {
void on_pending_message_views_timeout(DialogId dialog_id);
bool update_message_views(DialogId dialog_id, Message *m, int32 views);
void update_message_interaction_info(FullMessageId full_message_id, int32 view_count, int32 forward_count,
bool has_reply_info, tl_object_ptr<telegram_api::messageReplies> &&reply_info);
td_api::object_ptr<td_api::messageInteractionInfo> get_message_interaction_info_object(DialogId dialog_id,
const Message *m) const;
bool update_message_interaction_info(DialogId dialog_id, Message *m, int32 view_count, int32 forward_count,
bool has_reply_info, MessageReplyInfo &&reply_info);
bool update_message_contains_unread_mention(Dialog *d, Message *m, bool contains_unread_mention, const char *source);
@ -2459,17 +2496,17 @@ class MessagesManager : public Actor {
void on_get_message_link_dialog(MessageLinkInfo &&info, Promise<MessageLinkInfo> &&promise);
static MessageId get_first_database_message_id_by_index(const Dialog *d, SearchMessagesFilter filter);
static MessageId get_first_database_message_id_by_index(const Dialog *d, MessageSearchFilter filter);
void on_search_dialog_messages_db_result(int64 random_id, DialogId dialog_id, MessageId from_message_id,
MessageId first_db_message_id, SearchMessagesFilter filter_type,
int32 offset, int32 limit, Result<std::vector<BufferSlice>> r_messages,
Promise<> promise);
MessageId first_db_message_id, MessageSearchFilter filter, int32 offset,
int32 limit, Result<std::vector<BufferSlice>> r_messages, Promise<> promise);
void on_messages_db_fts_result(Result<MessagesDbFtsResult> result, int64 random_id, Promise<> &&promise);
void on_messages_db_fts_result(Result<MessagesDbFtsResult> result, string offset, int32 limit, int64 random_id,
Promise<> &&promise);
void on_messages_db_calls_result(Result<MessagesDbCallsResult> result, int64 random_id, MessageId first_db_message_id,
SearchMessagesFilter filter, Promise<Unit> &&promise);
MessageSearchFilter filter, Promise<Unit> &&promise);
void on_load_active_live_location_full_message_ids_from_database(string value);
@ -2690,6 +2727,8 @@ class MessagesManager : public Actor {
void update_top_dialogs(DialogId dialog_id, const Message *m);
void update_forward_count(DialogId dialog_id, MessageId message_id);
void try_hide_distance(DialogId dialog_id, const Message *m);
string get_message_search_text(const Message *m) const;
@ -2914,8 +2953,8 @@ class MessagesManager : public Actor {
std::unordered_map<int64, std::pair<int32, vector<MessageId>>>
found_dialog_recent_location_messages_; // random_id -> [total_count, [message_id]...]
std::unordered_map<int64, std::pair<int64, vector<FullMessageId>>>
found_fts_messages_; // random_id -> [from_search_id, [full_message_id]...]
std::unordered_map<int64, FoundMessages> found_fts_messages_; // random_id -> FoundMessages
std::unordered_map<int64, FoundMessages> found_message_public_forwards_; // random_id -> FoundMessages
std::unordered_map<FullMessageId, std::pair<string, string>, FullMessageIdHash> public_message_links_[2];

View File

@ -395,6 +395,24 @@ Variant<PhotoSize, string> get_photo_size(FileManager *file_manager, PhotoSizeSo
auto size = move_tl_object_as<telegram_api::photoStrippedSize>(size_ptr);
return size->bytes_.as_slice().str();
}
case telegram_api::photoSizeProgressive::ID: {
auto size = move_tl_object_as<telegram_api::photoSizeProgressive>(size_ptr);
if (size->sizes_.empty()) {
LOG(ERROR) << "Receive " << to_string(size);
return std::move(res);
}
std::sort(size->sizes_.begin(), size->sizes_.end());
type = std::move(size->type_);
location = std::move(size->location_);
res.dimensions = get_dimensions(size->w_, size->h_);
res.size = size->sizes_.back();
size->sizes_.pop_back();
res.progressive_sizes = std::move(size->sizes_);
break;
}
default:
UNREACHABLE();
break;
@ -554,7 +572,8 @@ static tl_object_ptr<td_api::photoSize> get_photo_size_object(FileManager *file_
return td_api::make_object<td_api::photoSize>(
photo_size->type ? std::string(1, static_cast<char>(photo_size->type))
: std::string(), // TODO replace string type with integer type
file_manager->get_file_object(photo_size->file_id), photo_size->dimensions.width, photo_size->dimensions.height);
file_manager->get_file_object(photo_size->file_id), photo_size->dimensions.width, photo_size->dimensions.height,
vector<int32>(photo_size->progressive_sizes));
}
static vector<td_api::object_ptr<td_api::photoSize>> get_photo_sizes_object(FileManager *file_manager,
@ -573,7 +592,8 @@ static vector<td_api::object_ptr<td_api::photoSize>> get_photo_sizes_object(File
}
bool operator==(const PhotoSize &lhs, const PhotoSize &rhs) {
return lhs.type == rhs.type && lhs.dimensions == rhs.dimensions && lhs.size == rhs.size && lhs.file_id == rhs.file_id;
return lhs.type == rhs.type && lhs.dimensions == rhs.dimensions && lhs.size == rhs.size &&
lhs.file_id == rhs.file_id && lhs.progressive_sizes == rhs.progressive_sizes;
}
bool operator!=(const PhotoSize &lhs, const PhotoSize &rhs) {
@ -602,7 +622,8 @@ bool operator<(const PhotoSize &lhs, const PhotoSize &rhs) {
StringBuilder &operator<<(StringBuilder &string_builder, const PhotoSize &photo_size) {
return string_builder << "{type = " << photo_size.type << ", dimensions = " << photo_size.dimensions
<< ", size = " << photo_size.size << ", file_id = " << photo_size.file_id << "}";
<< ", size = " << photo_size.size << ", file_id = " << photo_size.file_id
<< ", progressive_sizes = " << photo_size.progressive_sizes << "}";
}
static tl_object_ptr<td_api::animatedChatPhoto> get_animated_chat_photo_object(FileManager *file_manager,
@ -936,6 +957,15 @@ tl_object_ptr<telegram_api::userProfilePhoto> convert_photo_to_profile_photo(
}
case telegram_api::photoStrippedSize::ID:
break;
case telegram_api::photoSizeProgressive::ID: {
auto size = static_cast<const telegram_api::photoSizeProgressive *>(size_ptr.get());
if (size->type_ == "a") {
photo_small = copy_location(size->location_);
} else if (size->type_ == "c") {
photo_big = copy_location(size->location_);
}
break;
}
default:
UNREACHABLE();
break;

View File

@ -48,6 +48,7 @@ struct PhotoSize {
Dimensions dimensions;
int32 size = 0;
FileId file_id;
vector<int32> progressive_sizes;
};
struct AnimationSize : public PhotoSize {

View File

@ -75,6 +75,7 @@ void store(const PhotoSize &photo_size, StorerT &storer) {
store(photo_size.dimensions, storer);
store(photo_size.size, storer);
store(photo_size.file_id, storer);
store(photo_size.progressive_sizes, storer);
}
template <class ParserT>
@ -83,6 +84,11 @@ void parse(PhotoSize &photo_size, ParserT &parser) {
parse(photo_size.dimensions, parser);
parse(photo_size.size, parser);
parse(photo_size.file_id, parser);
if (parser.version() >= static_cast<int32>(Version::AddPhotoProgressiveSizes)) {
parse(photo_size.progressive_sizes, parser);
} else {
photo_size.progressive_sizes.clear();
}
LOG(DEBUG) << "Parsed photo size " << photo_size;
}

View File

@ -84,6 +84,9 @@ static StringBuilder &operator<<(StringBuilder &string_builder, const InlineKeyb
case InlineKeyboardButton::Type::UrlAuth:
string_builder << "UrlAuth, id = " << keyboard_button.id;
break;
case InlineKeyboardButton::Type::CallbackWithPassword:
string_builder << "CallbackWithPassword";
break;
default:
UNREACHABLE();
}
@ -219,7 +222,8 @@ static InlineKeyboardButton get_inline_keyboard_button(
}
case telegram_api::keyboardButtonCallback::ID: {
auto keyboard_button = move_tl_object_as<telegram_api::keyboardButtonCallback>(keyboard_button_ptr);
button.type = InlineKeyboardButton::Type::Callback;
button.type = keyboard_button->requires_password_ ? InlineKeyboardButton::Type::CallbackWithPassword
: InlineKeyboardButton::Type::Callback;
button.text = std::move(keyboard_button->text_);
button.data = keyboard_button->data_.as_slice().str();
break;
@ -435,6 +439,8 @@ static Result<InlineKeyboardButton> get_inline_keyboard_button(tl_object_ptr<td_
case td_api::inlineKeyboardButtonTypeCallbackGame::ID:
current_button.type = InlineKeyboardButton::Type::CallbackGame;
break;
case td_api::inlineKeyboardButtonTypeCallbackWithPassword::ID:
return Status::Error(400, "Can't use CallbackWithPassword inline button");
case td_api::inlineKeyboardButtonTypeSwitchInline::ID: {
auto switch_inline_button = move_tl_object_as<td_api::inlineKeyboardButtonTypeSwitchInline>(button->type_);
if (!switch_inline_buttons_allowed) {
@ -618,7 +624,7 @@ static tl_object_ptr<telegram_api::KeyboardButton> get_inline_keyboard_button(
case InlineKeyboardButton::Type::Url:
return make_tl_object<telegram_api::keyboardButtonUrl>(keyboard_button.text, keyboard_button.data);
case InlineKeyboardButton::Type::Callback:
return make_tl_object<telegram_api::keyboardButtonCallback>(keyboard_button.text,
return make_tl_object<telegram_api::keyboardButtonCallback>(0, false /*ignored*/, keyboard_button.text,
BufferSlice(keyboard_button.data));
case InlineKeyboardButton::Type::CallbackGame:
return make_tl_object<telegram_api::keyboardButtonGame>(keyboard_button.text);
@ -653,6 +659,9 @@ static tl_object_ptr<telegram_api::KeyboardButton> get_inline_keyboard_button(
keyboard_button.forward_text,
keyboard_button.data, std::move(input_user));
}
case InlineKeyboardButton::Type::CallbackWithPassword:
UNREACHABLE();
break;
default:
UNREACHABLE();
return nullptr;
@ -762,6 +771,9 @@ static tl_object_ptr<td_api::inlineKeyboardButton> get_inline_keyboard_button_ob
type = make_tl_object<td_api::inlineKeyboardButtonTypeLoginUrl>(keyboard_button.data, keyboard_button.id,
keyboard_button.forward_text);
break;
case InlineKeyboardButton::Type::CallbackWithPassword:
type = make_tl_object<td_api::inlineKeyboardButtonTypeCallbackWithPassword>(keyboard_button.data);
break;
default:
UNREACHABLE();
return nullptr;

View File

@ -31,7 +31,16 @@ struct KeyboardButton {
struct InlineKeyboardButton {
// append only
enum class Type : int32 { Url, Callback, CallbackGame, SwitchInline, SwitchInlineCurrentDialog, Buy, UrlAuth };
enum class Type : int32 {
Url,
Callback,
CallbackGame,
SwitchInline,
SwitchInlineCurrentDialog,
Buy,
UrlAuth,
CallbackWithPassword
};
Type type;
int32 id = 0; // UrlAuth only, button_id or (2 * request_write_access - 1) * bot_user_id
string text;

View File

@ -324,7 +324,7 @@ void SecretChatActor::send_message_impl(tl_object_ptr<secret_api::DecryptedMessa
int64 random_id = 0;
downcast_call(*message, [&](auto &x) { random_id = x.random_id_; });
LOG(INFO) << "Send message: " << to_string(*message) << to_string(file);
LOG(INFO) << "Send message: " << to_string(message) << to_string(file);
auto it = random_id_to_outbound_message_state_token_.find(random_id);
if (it != random_id_to_outbound_message_state_token_.end()) {
@ -344,6 +344,9 @@ void SecretChatActor::send_message_impl(tl_object_ptr<secret_api::DecryptedMessa
.move_as_ok();
binlog_event->need_notify_user = (flags & SendFlag::Push) == 0;
binlog_event->is_external = (flags & SendFlag::External) != 0;
binlog_event->is_silent = (message->get_id() == secret_api::decryptedMessage::ID &&
(static_cast<const secret_api::decryptedMessage *>(message.get())->flags_ &
secret_api::decryptedMessage::SILENT_MASK) != 0);
if (message->get_id() == secret_api::decryptedMessageService::ID) {
binlog_event->is_rewritable = false;
auto service_message = move_tl_object_as<secret_api::decryptedMessageService>(message);
@ -1467,14 +1470,22 @@ NetQueryPtr SecretChatActor::create_net_query(const logevent::OutboundSecretMess
telegram_api::messages_sendEncryptedService(get_input_chat(), message.random_id,
message.encrypted_message.clone()));
} else if (message.file.empty()) {
int32 flags = 0;
if (message.is_silent) {
flags |= telegram_api::messages_sendEncrypted::SILENT_MASK;
}
query = create_net_query(
QueryType::Message,
telegram_api::messages_sendEncrypted(get_input_chat(), message.random_id, message.encrypted_message.clone()));
QueryType::Message, telegram_api::messages_sendEncrypted(flags, false /*ignored*/, get_input_chat(),
message.random_id, message.encrypted_message.clone()));
} else {
query = create_net_query(
QueryType::Message,
telegram_api::messages_sendEncryptedFile(get_input_chat(), message.random_id, message.encrypted_message.clone(),
message.file.as_input_encrypted_file()));
int32 flags = 0;
if (message.is_silent) {
flags |= telegram_api::messages_sendEncryptedFile::SILENT_MASK;
}
query = create_net_query(QueryType::Message,
telegram_api::messages_sendEncryptedFile(
flags, false /*ignored*/, get_input_chat(), message.random_id,
message.encrypted_message.clone(), message.file.as_input_encrypted_file()));
}
if (!message.is_rewritable) {
query->total_timeout_limit_ = 1000000000; // inf. We will re-sent it immediately anyway
@ -1562,6 +1573,7 @@ Status SecretChatActor::outbound_rewrite_with_empty(uint64 state_id) {
state->message->is_rewritable = false;
state->message->is_external = false;
state->message->need_notify_user = false;
state->message->is_silent = true;
state->message->file = logevent::EncryptedInputFile::from_input_encrypted_file(nullptr);
binlog_rewrite(context_->binlog(), state->message->logevent_id(), LogEvent::HandlerType::SecretChats,
create_storer(*state->message));

View File

@ -1280,7 +1280,8 @@ void SecureManager::send_passport_authorization_form(int32 authorization_form_id
send_with_promise(std::move(query), std::move(new_promise));
}
void SecureManager::get_preferred_country_code(string country_code, Promise<td_api::object_ptr<td_api::text>> promise) {
void SecureManager::get_preferred_country_language(string country_code,
Promise<td_api::object_ptr<td_api::text>> promise) {
refcnt_++;
for (auto &c : country_code) {
c = to_upper(c);

View File

@ -54,7 +54,7 @@ class SecureManager : public NetQueryCallback {
void send_passport_authorization_form(int32 authorization_form_id, std::vector<SecureValueType> types,
Promise<> promise);
void get_preferred_country_code(string country_code, Promise<td_api::object_ptr<td_api::text>> promise);
void get_preferred_country_language(string country_code, Promise<td_api::object_ptr<td_api::text>> promise);
private:
ActorShared<> parent_;

View File

@ -22,6 +22,7 @@
#include "td/telegram/ConfigManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/CountryInfoManager.h"
#include "td/telegram/DeviceTokenManager.h"
#include "td/telegram/DialogAdministrator.h"
#include "td/telegram/DialogFilter.h"
@ -50,6 +51,7 @@
#include "td/telegram/MessageCopyOptions.h"
#include "td/telegram/MessageEntity.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/MessageSearchFilter.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/misc.h"
#include "td/telegram/net/ConnectionCreator.h"
@ -155,35 +157,6 @@ void Td::ResultHandler::send_query(NetQueryPtr query) {
td->send(std::move(query));
}
class GetNearestDcQuery : public Td::ResultHandler {
Promise<string> promise_;
public:
explicit GetNearestDcQuery(Promise<string> &&promise) : promise_(std::move(promise)) {
}
void send() {
send_query(G()->net_query_creator().create_unauth(telegram_api::help_getNearestDc()));
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::help_getNearestDc>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
auto result = result_ptr.move_as_ok();
promise_.set_value(std::move(result->country_));
}
void on_error(uint64 id, Status status) override {
if (!G()->is_expected_error(status) && status.message() != "BOT_METHOD_INVALID") {
LOG(ERROR) << "GetNearestDc returned " << status;
}
promise_.set_error(std::move(status));
}
};
class GetPromoDataQuery : public Td::ResultHandler {
Promise<telegram_api::object_ptr<telegram_api::help_PromoData>> promise_;
@ -1424,7 +1397,7 @@ class SearchChatMessagesRequest : public RequestActor<> {
MessageId from_message_id_;
int32 offset_;
int32 limit_;
tl_object_ptr<td_api::SearchMessagesFilter> filter_;
MessageSearchFilter filter_;
int64 random_id_;
std::pair<int32, vector<MessageId>> messages_;
@ -1459,46 +1432,40 @@ class SearchChatMessagesRequest : public RequestActor<> {
, from_message_id_(from_message_id)
, offset_(offset)
, limit_(limit)
, filter_(std::move(filter))
, filter_(get_message_search_filter(filter))
, random_id_(0) {
set_tries(3);
}
};
class OfflineSearchMessagesRequest : public RequestActor<> {
class SearchSecretMessagesRequest : public RequestActor<> {
DialogId dialog_id_;
string query_;
int64 from_search_id_;
string offset_;
int32 limit_;
tl_object_ptr<td_api::SearchMessagesFilter> filter_;
MessageSearchFilter filter_;
int64 random_id_;
std::pair<int64, vector<FullMessageId>> messages_;
MessagesManager::FoundMessages found_messages_;
void do_run(Promise<Unit> &&promise) override {
messages_ = td->messages_manager_->offline_search_messages(dialog_id_, query_, from_search_id_, limit_, filter_,
found_messages_ = td->messages_manager_->offline_search_messages(dialog_id_, query_, offset_, limit_, filter_,
random_id_, std::move(promise));
}
void do_send_result() override {
vector<tl_object_ptr<td_api::message>> result;
result.reserve(messages_.second.size());
for (auto full_message_id : messages_.second) {
result.push_back(td->messages_manager_->get_message_object(full_message_id));
}
send_result(make_tl_object<td_api::foundMessages>(std::move(result), messages_.first));
send_result(td->messages_manager_->get_found_messages_object(found_messages_));
}
public:
OfflineSearchMessagesRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, string query,
int64 from_search_id, int32 limit, tl_object_ptr<td_api::SearchMessagesFilter> filter)
SearchSecretMessagesRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, string query, string offset,
int32 limit, tl_object_ptr<td_api::SearchMessagesFilter> filter)
: RequestActor(std::move(td), request_id)
, dialog_id_(dialog_id)
, query_(std::move(query))
, from_search_id_(from_search_id)
, offset_(std::move(offset))
, limit_(limit)
, filter_(std::move(filter))
, filter_(get_message_search_filter(filter))
, random_id_(0) {
}
};
@ -1511,6 +1478,7 @@ class SearchMessagesRequest : public RequestActor<> {
DialogId offset_dialog_id_;
MessageId offset_message_id_;
int32 limit_;
MessageSearchFilter filter_;
int64 random_id_;
std::pair<int32, vector<FullMessageId>> messages_;
@ -1518,7 +1486,7 @@ class SearchMessagesRequest : public RequestActor<> {
void do_run(Promise<Unit> &&promise) override {
messages_ =
td->messages_manager_->search_messages(folder_id_, ignore_folder_id_, query_, offset_date_, offset_dialog_id_,
offset_message_id_, limit_, random_id_, std::move(promise));
offset_message_id_, limit_, filter_, random_id_, std::move(promise));
}
void do_send_result() override {
@ -1536,7 +1504,8 @@ class SearchMessagesRequest : public RequestActor<> {
public:
SearchMessagesRequest(ActorShared<Td> td, uint64 request_id, FolderId folder_id, bool ignore_folder_id, string query,
int32 offset_date, int64 offset_dialog_id, int64 offset_message_id, int32 limit)
int32 offset_date, int64 offset_dialog_id, int64 offset_message_id, int32 limit,
tl_object_ptr<td_api::SearchMessagesFilter> &&filter)
: RequestActor(std::move(td), request_id)
, folder_id_(folder_id)
, ignore_folder_id_(ignore_folder_id)
@ -1545,6 +1514,7 @@ class SearchMessagesRequest : public RequestActor<> {
, offset_dialog_id_(offset_dialog_id)
, offset_message_id_(offset_message_id)
, limit_(limit)
, filter_(get_message_search_filter(filter))
, random_id_(0) {
}
};
@ -1638,7 +1608,7 @@ class GetChatMessageByDateRequest : public RequestOnceActor {
class GetChatMessageCountRequest : public RequestActor<> {
DialogId dialog_id_;
tl_object_ptr<td_api::SearchMessagesFilter> filter_;
MessageSearchFilter filter_;
bool return_local_;
int64 random_id_;
@ -1658,7 +1628,7 @@ class GetChatMessageCountRequest : public RequestActor<> {
tl_object_ptr<td_api::SearchMessagesFilter> filter, bool return_local)
: RequestActor(std::move(td), request_id)
, dialog_id_(dialog_id)
, filter_(std::move(filter))
, filter_(get_message_search_filter(filter))
, return_local_(return_local)
, random_id_(0) {
}
@ -1685,6 +1655,34 @@ class GetChatScheduledMessagesRequest : public RequestActor<> {
}
};
class GetMessagePublicForwardsRequest : public RequestActor<> {
FullMessageId full_message_id_;
string offset_;
int32 limit_;
int64 random_id_;
MessagesManager::FoundMessages messages_;
void do_run(Promise<Unit> &&promise) override {
messages_ = td->messages_manager_->get_message_public_forwards(full_message_id_, offset_, limit_, random_id_,
std::move(promise));
}
void do_send_result() override {
send_result(td->messages_manager_->get_found_messages_object(messages_));
}
public:
GetMessagePublicForwardsRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, int64 message_id,
string offset, int32 limit)
: RequestActor(std::move(td), request_id)
, full_message_id_(DialogId(dialog_id), MessageId(message_id))
, offset_(std::move(offset))
, limit_(limit)
, random_id_(0) {
}
};
class GetWebPagePreviewRequest : public RequestOnceActor {
td_api::object_ptr<td_api::formattedText> text_;
@ -1875,10 +1873,6 @@ class GetChatMemberRequest : public RequestActor<> {
send_result(td->contacts_manager_->get_chat_member_object(dialog_participant_));
}
void do_send_error(Status &&status) override {
send_error(std::move(status));
}
public:
GetChatMemberRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, int32 user_id)
: RequestActor(std::move(td), request_id), dialog_id_(dialog_id), user_id_(user_id), random_id_(0) {
@ -2901,7 +2895,8 @@ class GetCallbackQueryAnswerRequest : public RequestOnceActor {
int64 result_id_;
void do_run(Promise<Unit> &&promise) override {
result_id_ = td->callback_queries_manager_->send_callback_query(full_message_id_, payload_, std::move(promise));
result_id_ =
td->callback_queries_manager_->send_callback_query(full_message_id_, std::move(payload_), std::move(promise));
}
void do_send_result() override {
@ -3007,6 +3002,7 @@ class SetBackgroundRequest : public RequestActor<> {
Td::Td(unique_ptr<TdCallback> callback, Options options)
: callback_(std::move(callback)), td_options_(std::move(options)) {
CHECK(callback_ != nullptr);
}
Td::~Td() = default;
@ -3302,7 +3298,9 @@ bool Td::is_preauthentication_request(int32 id) {
case td_api::getNetworkStatistics::ID:
case td_api::addNetworkStatistics::ID:
case td_api::resetNetworkStatistics::ID:
case td_api::getCountries::ID:
case td_api::getCountryCode::ID:
case td_api::getPhoneNumberInfo::ID:
case td_api::getDeepLinkInfo::ID:
case td_api::getApplicationConfig::ID:
case td_api::saveApplicationLogEvent::ID:
@ -3724,7 +3722,7 @@ void Td::start_up() {
}
VLOG(td_init) << "Create Global";
set_context(std::make_shared<Global>());
old_context_ = set_context(std::make_shared<Global>());
G()->set_net_query_stats(td_options_.net_query_stats);
inc_request_actor_refcnt(); // guard
inc_actor_refcnt(); // guard
@ -3774,6 +3772,7 @@ void Td::inc_actor_refcnt() {
void Td::dec_actor_refcnt() {
actor_refcnt_--;
LOG(DEBUG) << "Decrease reference count to " << actor_refcnt_;
if (actor_refcnt_ == 0) {
if (close_flag_ == 2) {
create_reference();
@ -3789,8 +3788,12 @@ void Td::dec_actor_refcnt() {
LOG(DEBUG) << "AuthManager was cleared" << timer;
background_manager_.reset();
LOG(DEBUG) << "BackgroundManager was cleared" << timer;
callback_queries_manager_.reset();
LOG(DEBUG) << "CallbackQueriesManager was cleared" << timer;
contacts_manager_.reset();
LOG(DEBUG) << "ContactsManager was cleared" << timer;
country_info_manager_.reset();
LOG(DEBUG) << "CountryInfoManager was cleared" << timer;
documents_manager_.reset();
LOG(DEBUG) << "DocumentsManager was cleared" << timer;
file_manager_.reset();
@ -3847,6 +3850,7 @@ void Td::dec_stop_cnt() {
stop_cnt_--;
if (stop_cnt_ == 0) {
LOG(WARNING) << "Stop Td";
set_context(std::move(old_context_));
stop();
}
}
@ -3857,6 +3861,7 @@ void Td::inc_request_actor_refcnt() {
void Td::dec_request_actor_refcnt() {
request_actor_refcnt_--;
LOG(DEBUG) << "Decrease request actor count to " << request_actor_refcnt_;
if (request_actor_refcnt_ == 0) {
LOG(WARNING) << "Have no request actors";
clear();
@ -3973,6 +3978,8 @@ void Td::clear() {
LOG(DEBUG) << "BackgroundManager actor was cleared" << timer;
contacts_manager_actor_.reset();
LOG(DEBUG) << "ContactsManager actor was cleared" << timer;
country_info_manager_actor_.reset();
LOG(DEBUG) << "CountryInfoManager actor was cleared" << timer;
file_manager_actor_.reset();
LOG(DEBUG) << "FileManager actor was cleared" << timer;
file_reference_manager_actor_.reset();
@ -4205,7 +4212,7 @@ Status Td::init(DbKey key) {
VLOG(td_init) << "Ping datacenter";
if (!auth_manager_->is_authorized()) {
send_get_nearest_dc_query(Promise<string>());
country_info_manager_->get_current_country_code(Promise<string>());
} else {
updates_manager_->get_difference("init");
schedule_get_terms_of_service(0);
@ -4412,6 +4419,8 @@ void Td::init_managers() {
contacts_manager_ = make_unique<ContactsManager>(this, create_reference());
contacts_manager_actor_ = register_actor("ContactsManager", contacts_manager_.get());
G()->set_contacts_manager(contacts_manager_actor_.get());
country_info_manager_ = make_unique<CountryInfoManager>(this, create_reference());
country_info_manager_actor_ = register_actor("CountryInfoManager", country_info_manager_.get());
inline_queries_manager_ = make_unique<InlineQueriesManager>(this, create_reference());
inline_queries_manager_actor_ = register_actor("InlineQueriesManager", inline_queries_manager_.get());
messages_manager_ = make_unique<MessagesManager>(this, create_reference());
@ -4454,10 +4463,6 @@ void Td::init_managers() {
"VerifyPhoneNumberManager", PhoneNumberManager::Type::VerifyPhone, create_reference());
}
void Td::send_get_nearest_dc_query(Promise<string> promise) {
create_handler<GetNearestDcQuery>(std::move(promise))->send();
}
void Td::send_update(tl_object_ptr<td_api::Update> &&object) {
CHECK(object != nullptr);
auto object_id = object->get_id();
@ -4516,7 +4521,6 @@ void Td::send_result(uint64 id, tl_object_ptr<td_api::Object> object) {
void Td::send_error_impl(uint64 id, tl_object_ptr<td_api::error> error) {
CHECK(id != 0);
CHECK(callback_ != nullptr);
CHECK(error != nullptr);
auto it = request_set_.find(id);
if (it != request_set_.end()) {
@ -5479,7 +5483,8 @@ void Td::on_request(uint64 id, td_api::searchChatMessages &request) {
void Td::on_request(uint64 id, td_api::searchSecretMessages &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.query_);
CREATE_REQUEST(OfflineSearchMessagesRequest, request.chat_id_, std::move(request.query_), request.from_search_id_,
CLEAN_INPUT_STRING(request.offset_);
CREATE_REQUEST(SearchSecretMessagesRequest, request.chat_id_, std::move(request.query_), std::move(request.offset_),
request.limit_, std::move(request.filter_));
}
@ -5492,7 +5497,7 @@ void Td::on_request(uint64 id, td_api::searchMessages &request) {
}
CREATE_REQUEST(SearchMessagesRequest, dialog_list_id.get_folder_id(), request.chat_list_ == nullptr,
std::move(request.query_), request.offset_date_, request.offset_chat_id_, request.offset_message_id_,
request.limit_);
request.limit_, std::move(request.filter_));
}
void Td::on_request(uint64 id, td_api::searchCallMessages &request) {
@ -5524,6 +5529,13 @@ void Td::on_request(uint64 id, const td_api::getChatScheduledMessages &request)
CREATE_REQUEST(GetChatScheduledMessagesRequest, request.chat_id_);
}
void Td::on_request(uint64 id, td_api::getMessagePublicForwards &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.offset_);
CREATE_REQUEST(GetMessagePublicForwardsRequest, request.chat_id_, request.message_id_, request.offset_,
request.limit_);
}
void Td::on_request(uint64 id, const td_api::removeNotification &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
@ -6745,7 +6757,14 @@ void Td::on_request(uint64 id, const td_api::getChatStatistics &request) {
contacts_manager_->get_channel_statistics(DialogId(request.chat_id_), request.is_dark_, std::move(promise));
}
void Td::on_request(uint64 id, td_api::getChatStatisticsGraph &request) {
void Td::on_request(uint64 id, const td_api::getMessageStatistics &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
contacts_manager_->get_channel_message_statistics({DialogId(request.chat_id_), MessageId(request.message_id_)},
request.is_dark_, std::move(promise));
}
void Td::on_request(uint64 id, td_api::getStatisticsGraph &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
CLEAN_INPUT_STRING(request.token_);
@ -7466,7 +7485,7 @@ void Td::on_request(uint64 id, td_api::getPreferredCountryLanguage &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.country_code_);
CREATE_REQUEST_PROMISE();
send_closure(secure_manager_, &SecureManager::get_preferred_country_code, std::move(request.country_code_),
send_closure(secure_manager_, &SecureManager::get_preferred_country_language, std::move(request.country_code_),
std::move(promise));
}
@ -7688,6 +7707,11 @@ void Td::on_request(uint64 id, td_api::acceptTermsOfService &request) {
accept_terms_of_service(this, std::move(request.terms_of_service_id_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getCountries &request) {
CREATE_REQUEST_PROMISE();
country_info_manager_->get_countries(std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getCountryCode &request) {
CREATE_REQUEST_PROMISE();
auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result<string> result) mutable {
@ -7697,7 +7721,12 @@ void Td::on_request(uint64 id, const td_api::getCountryCode &request) {
promise.set_value(make_tl_object<td_api::text>(result.move_as_ok()));
}
});
create_handler<GetNearestDcQuery>(std::move(query_promise))->send();
country_info_manager_->get_current_country_code(std::move(query_promise));
}
void Td::on_request(uint64 id, const td_api::getPhoneNumberInfo &request) {
CREATE_REQUEST_PROMISE();
country_info_manager_->get_phone_number_info(request.phone_number_prefix_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getInviteText &request) {

View File

@ -52,6 +52,7 @@ class CallManager;
class CallbackQueriesManager;
class ConfigManager;
class ContactsManager;
class CountryInfoManager;
class DeviceTokenManager;
class DocumentsManager;
class FileManager;
@ -155,6 +156,8 @@ class Td final : public NetQueryCallback {
ActorOwn<BackgroundManager> background_manager_actor_;
unique_ptr<ContactsManager> contacts_manager_;
ActorOwn<ContactsManager> contacts_manager_actor_;
unique_ptr<CountryInfoManager> country_info_manager_;
ActorOwn<CountryInfoManager> country_info_manager_actor_;
unique_ptr<FileManager> file_manager_;
ActorOwn<FileManager> file_manager_actor_;
unique_ptr<FileReferenceManager> file_reference_manager_;
@ -353,6 +356,8 @@ class Td final : public NetQueryCallback {
std::shared_ptr<UploadFileCallback> upload_file_callback_;
std::shared_ptr<ActorContext> old_context_;
static int *get_log_verbosity_level(Slice name);
template <class T>
@ -589,6 +594,8 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::getChatScheduledMessages &request);
void on_request(uint64 id, td_api::getMessagePublicForwards &request);
void on_request(uint64 id, const td_api::removeNotification &request);
void on_request(uint64 id, const td_api::removeNotificationGroup &request);
@ -919,7 +926,9 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::getChatStatistics &request);
void on_request(uint64 id, td_api::getChatStatisticsGraph &request);
void on_request(uint64 id, const td_api::getMessageStatistics &request);
void on_request(uint64 id, td_api::getStatisticsGraph &request);
void on_request(uint64 id, const td_api::getMapThumbnailFile &request);
@ -1051,8 +1060,12 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, td_api::acceptTermsOfService &request);
void on_request(uint64 id, const td_api::getCountries &request);
void on_request(uint64 id, const td_api::getCountryCode &request);
void on_request(uint64 id, const td_api::getPhoneNumberInfo &request);
void on_request(uint64 id, const td_api::getInviteText &request);
void on_request(uint64 id, td_api::getDeepLinkInfo &request);
@ -1169,8 +1182,6 @@ class Td final : public NetQueryCallback {
static Status fix_parameters(TdParameters &parameters) TD_WARN_UNUSED_RESULT;
Status set_parameters(td_api::object_ptr<td_api::tdlibParameters> parameters) TD_WARN_UNUSED_RESULT;
void send_get_nearest_dc_query(Promise<string> promise);
static td_api::object_ptr<td_api::error> make_error(int32 code, CSlice error) {
return td_api::make_object<td_api::error>(code, error.str());
}

View File

@ -506,6 +506,17 @@ bool UpdatesManager::is_acceptable_message(const telegram_api::Message *message_
CHECK(message->media_ == nullptr);
}
/*
// the users are always min, so no need to check
if (message->replies_ != nullptr) {
for (auto &user_id : message->replies_->recent_repliers_) {
if (!is_acceptable_user(UserId(user_id))) {
return false;
}
}
}
*/
break;
}
case telegram_api::messageService::ID: {
@ -695,8 +706,8 @@ void UpdatesManager::on_get_updates(tl_object_ptr<telegram_api::Updates> &&updat
update->flags_, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, update->id_, from_id,
make_tl_object<telegram_api::peerUser>(update->user_id_), std::move(update->fwd_from_),
update->via_bot_id_, update->reply_to_msg_id_, update->date_, update->message_, nullptr, nullptr,
std::move(update->entities_), 0, 0, "", 0, Auto()),
update->via_bot_id_, update->reply_to_msg_id_, 0, update->date_, update->message_, nullptr, nullptr,
std::move(update->entities_), 0, 0, nullptr, 0, string(), 0, Auto()),
update->pts_, update->pts_count_),
0, "telegram_api::updatesShortMessage");
break;
@ -713,14 +724,14 @@ void UpdatesManager::on_get_updates(tl_object_ptr<telegram_api::Updates> &&updat
}
update->flags_ |= MessagesManager::MESSAGE_FLAG_HAS_FROM_ID;
on_pending_update(
make_tl_object<telegram_api::updateNewMessage>(
on_pending_update(make_tl_object<telegram_api::updateNewMessage>(
make_tl_object<telegram_api::message>(
update->flags_, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, update->id_,
update->from_id_, make_tl_object<telegram_api::peerChat>(update->chat_id_),
std::move(update->fwd_from_), update->via_bot_id_, update->reply_to_msg_id_, update->date_,
update->message_, nullptr, nullptr, std::move(update->entities_), 0, 0, "", 0, Auto()),
update->flags_, false /*ignored*/, false /*ignored*/, false /*ignored*/,
false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
false /*ignored*/, update->id_, update->from_id_,
make_tl_object<telegram_api::peerChat>(update->chat_id_), std::move(update->fwd_from_),
update->via_bot_id_, update->reply_to_msg_id_, 0, update->date_, update->message_,
nullptr, nullptr, std::move(update->entities_), 0, 0, nullptr, 0, string(), 0, Auto()),
update->pts_, update->pts_count_),
0, "telegram_api::updatesShortChatMessage");
break;
@ -1684,7 +1695,19 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannelMessageV
return;
}
DialogId dialog_id(channel_id);
td_->messages_manager_->on_update_message_views({dialog_id, MessageId(ServerMessageId(update->id_))}, update->views_);
td_->messages_manager_->on_update_message_view_count({dialog_id, MessageId(ServerMessageId(update->id_))},
update->views_);
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannelMessageForwards> update, bool /*force_apply*/) {
ChannelId channel_id(update->channel_id_);
if (!channel_id.is_valid()) {
LOG(ERROR) << "Receive invalid " << channel_id;
return;
}
DialogId dialog_id(channel_id);
td_->messages_manager_->on_update_message_forward_count({dialog_id, MessageId(ServerMessageId(update->id_))},
update->forwards_);
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannelAvailableMessages> update,
@ -2174,4 +2197,7 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannelParticip
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateTheme> update, bool /*force_apply*/) {
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateReadDiscussion> update, bool /*force_apply*/) {
}
} // namespace td

View File

@ -243,6 +243,7 @@ class UpdatesManager : public Actor {
void on_update(tl_object_ptr<telegram_api::updateEditChannelMessage> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateDeleteChannelMessages> update, bool force_apply);
void on_update(tl_object_ptr<telegram_api::updateChannelMessageViews> update, bool force_apply);
void on_update(tl_object_ptr<telegram_api::updateChannelMessageForwards> update, bool force_apply);
void on_update(tl_object_ptr<telegram_api::updateChannelAvailableMessages> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateUserPinnedMessage> update, bool /*force_apply*/);
@ -314,6 +315,8 @@ class UpdatesManager : public Actor {
// unsupported updates
void on_update(tl_object_ptr<telegram_api::updateTheme> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateReadDiscussion> update, bool /*force_apply*/);
};
} // namespace td

View File

@ -8,7 +8,7 @@
namespace td {
constexpr int32 MTPROTO_LAYER = 117;
constexpr int32 MTPROTO_LAYER = 119;
enum class Version : int32 {
Initial, // 0
@ -39,6 +39,7 @@ enum class Version : int32 {
AddDiceEmoji, // 25
AddAnimationStickers,
AddDialogPhotoHasAnimation,
AddPhotoProgressiveSizes,
Next
};

View File

@ -1013,7 +1013,7 @@ class CliClient final : public Actor {
return nullptr;
}
static td_api::object_ptr<td_api::SearchMessagesFilter> get_search_messages_filter(MutableSlice filter) {
static td_api::object_ptr<td_api::SearchMessagesFilter> as_search_messages_filter(MutableSlice filter) {
filter = trim(filter);
to_lower_inplace(filter);
if (filter == "an" || filter == "animation") {
@ -1848,6 +1848,18 @@ class CliClient final : public Actor {
} else if (op == "gcsm") {
string chat_id = args;
send_request(td_api::make_object<td_api::getChatScheduledMessages>(as_chat_id(chat_id)));
} else if (op == "gmpf") {
string chat_id;
string message_id;
string offset;
string limit;
std::tie(chat_id, args) = split(args);
std::tie(message_id, args) = split(args);
std::tie(offset, limit) = split(args);
send_request(td_api::make_object<td_api::getMessagePublicForwards>(as_chat_id(chat_id), as_message_id(message_id),
offset, to_integer<int32>(limit)));
} else if (op == "ghf") {
get_history_chat_id_ = as_chat_id(args);
@ -1862,9 +1874,11 @@ class CliClient final : public Actor {
string from_date;
string limit;
string query;
string filter;
std::tie(query, args) = split(args);
std::tie(limit, from_date) = split(args);
std::tie(limit, args) = split(args);
std::tie(filter, from_date) = split(args);
if (from_date.empty()) {
from_date = "0";
}
@ -1876,7 +1890,8 @@ class CliClient final : public Actor {
chat_list = td_api::make_object<td_api::chatListMain>();
}
send_request(td_api::make_object<td_api::searchMessages>(
std::move(chat_list), query, to_integer<int32>(from_date), 2147482647, 0, to_integer<int32>(limit)));
std::move(chat_list), query, to_integer<int32>(from_date), 2147482647, 0, to_integer<int32>(limit),
as_search_messages_filter(filter)));
} else if (op == "SCM") {
string chat_id;
string limit;
@ -1937,7 +1952,7 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::searchChatMessages>(
as_chat_id(chat_id), "", 0, as_message_id(offset_message_id), to_integer<int32>(offset),
to_integer<int32>(limit), get_search_messages_filter(filter)));
to_integer<int32>(limit), as_search_messages_filter(filter)));
} else if (op == "SC") {
string limit;
string offset_message_id;
@ -2046,7 +2061,7 @@ class CliClient final : public Actor {
std::tie(filter, return_local) = split(args);
send_request(td_api::make_object<td_api::getChatMessageCount>(
as_chat_id(chat_id), get_search_messages_filter(filter), as_bool(return_local)));
as_chat_id(chat_id), as_search_messages_filter(filter), as_bool(return_local)));
} else if (op == "gup" || op == "gupp") {
string user_id;
string offset;
@ -2258,8 +2273,12 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::removeBackground>(to_integer<int64>(args)));
} else if (op == "rbgs") {
send_request(td_api::make_object<td_api::resetBackgrounds>());
} else if (op == "gccode") {
} else if (op == "gcos") {
send_request(td_api::make_object<td_api::getCountries>());
} else if (op == "gcoc") {
send_request(td_api::make_object<td_api::getCountryCode>());
} else if (op == "gpni") {
send_request(td_api::make_object<td_api::getPhoneNumberInfo>(args));
} else if (op == "git") {
send_request(td_api::make_object<td_api::getInviteText>());
} else if (op == "atos") {
@ -2758,9 +2777,11 @@ class CliClient final : public Actor {
vector<td_api::object_ptr<td_api::CallProblem>> problems;
problems.emplace_back(td_api::make_object<td_api::callProblemNoise>());
problems.emplace_back(td_api::make_object<td_api::callProblemNoise>());
problems.emplace_back(td_api::make_object<td_api::callProblemDistortedVideo>());
problems.emplace_back(nullptr);
problems.emplace_back(td_api::make_object<td_api::callProblemNoise>());
problems.emplace_back(td_api::make_object<td_api::callProblemEcho>());
problems.emplace_back(td_api::make_object<td_api::callProblemPixelatedVideo>());
problems.emplace_back(td_api::make_object<td_api::callProblemDistortedSpeech>());
send_request(td_api::make_object<td_api::sendCallRating>(
as_call_id(call_id), to_integer<int32>(rating), "Wow, such good call! (TDLib test)", std::move(problems)));
@ -2918,19 +2939,18 @@ class CliClient final : public Actor {
}
} else if (op == "ssm") {
string chat_id;
string from_search_id;
string offset;
string limit;
string filter;
string query;
std::tie(chat_id, args) = split(args);
std::tie(from_search_id, args) = split(args);
std::tie(offset, args) = split(args);
std::tie(limit, args) = split(args);
std::tie(filter, query) = split(args);
send_request(td_api::make_object<td_api::searchSecretMessages>(
as_chat_id(chat_id), query, to_integer<int64>(from_search_id), to_integer<int32>(limit),
get_search_messages_filter(filter)));
as_chat_id(chat_id), query, offset, to_integer<int32>(limit), as_search_messages_filter(filter)));
} else if (op == "ssd") {
schedule_date_ = args;
} else if (op == "sm" || op == "sms" || op == "smr" || op == "smf") {
@ -3105,7 +3125,7 @@ class CliClient final : public Actor {
auto chat = as_chat_id(chat_id);
send_request(td_api::make_object<td_api::sendInlineQueryResultMessage>(
chat, 0, default_message_send_options(), to_integer<int64>(query_id), result_id, op == "siqrh"));
} else if (op == "gcqr") {
} else if (op == "gcqa") {
string chat_id;
string message_id;
string data;
@ -3113,7 +3133,18 @@ class CliClient final : public Actor {
std::tie(message_id, data) = split(args);
send_request(td_api::make_object<td_api::getCallbackQueryAnswer>(
as_chat_id(chat_id), as_message_id(message_id), td_api::make_object<td_api::callbackQueryPayloadData>(data)));
} else if (op == "gcgqr") {
} else if (op == "gcpqa") {
string chat_id;
string message_id;
string password;
string data;
std::tie(chat_id, args) = split(args);
std::tie(message_id, args) = split(args);
std::tie(password, data) = split(args);
send_request(td_api::make_object<td_api::getCallbackQueryAnswer>(
as_chat_id(chat_id), as_message_id(message_id),
td_api::make_object<td_api::callbackQueryPayloadDataWithPassword>(password, data)));
} else if (op == "gcgqa") {
string chat_id;
string message_id;
std::tie(chat_id, message_id) = split(args);
@ -4022,15 +4053,23 @@ class CliClient final : public Actor {
std::tie(chat_id, is_dark) = split(args);
send_request(td_api::make_object<td_api::getChatStatistics>(as_chat_id(chat_id), as_bool(is_dark)));
} else if (op == "gcstg") {
} else if (op == "gmst") {
string chat_id;
string message_id;
string is_dark;
std::tie(chat_id, args) = split(args);
std::tie(message_id, is_dark) = split(args);
send_request(td_api::make_object<td_api::getMessageStatistics>(as_chat_id(chat_id), as_message_id(message_id),
as_bool(is_dark)));
} else if (op == "gstg") {
string chat_id;
string token;
string x;
std::tie(chat_id, args) = split(args);
std::tie(token, x) = split(args);
send_request(
td_api::make_object<td_api::getChatStatisticsGraph>(as_chat_id(chat_id), token, to_integer<int64>(x)));
send_request(td_api::make_object<td_api::getStatisticsGraph>(as_chat_id(chat_id), token, to_integer<int64>(x)));
} else if (op == "hsa" || op == "glu" || op == "glua") {
send_request(td_api::make_object<td_api::hideSuggestedAction>(as_suggested_action(args)));
} else if (op == "glui" || op == "glu" || op == "glua") {

View File

@ -42,7 +42,11 @@ size_t FileLoader::get_part_size() const {
}
void FileLoader::hangup() {
if (delay_dispatcher_.empty()) {
stop();
} else {
delay_dispatcher_.reset();
}
}
void FileLoader::hangup_shared() {

View File

@ -330,6 +330,7 @@ class OutboundSecretMessage : public SecretChatLogEventBase<OutboundSecretMessag
bool is_rewritable = false;
// should notify our parent about state of this message (using context and random_id)
bool is_external = false;
bool is_silent = false;
tl_object_ptr<secret_api::DecryptedMessageAction> action;
uint64 crc = 0; // DEBUG;
@ -360,6 +361,7 @@ class OutboundSecretMessage : public SecretChatLogEventBase<OutboundSecretMessag
STORE_FLAG(has_action);
STORE_FLAG(is_rewritable);
STORE_FLAG(is_external);
STORE_FLAG(is_silent);
END_STORE_FLAGS();
if (has_action) {
@ -390,6 +392,7 @@ class OutboundSecretMessage : public SecretChatLogEventBase<OutboundSecretMessag
PARSE_FLAG(has_action);
PARSE_FLAG(is_rewritable);
PARSE_FLAG(is_external);
PARSE_FLAG(is_silent);
END_PARSE_FLAGS();
if (has_action) {

View File

@ -352,8 +352,9 @@ class NetQuery : public TsListNode<NetQueryDebug> {
, answer_(std::move(answer))
, tl_constructor_(tl_constructor)
, total_timeout_limit_(total_timeout_limit) {
get_data_unsafe().my_id_ = get_my_id();
get_data_unsafe().start_timestamp_ = Time::now();
auto &data = get_data_unsafe();
data.my_id_ = get_my_id();
data.start_timestamp_ = data.state_timestamp_ = Time::now();
LOG(INFO) << *this;
if (stats) {
nq_counter_ = stats->register_query(this);

View File

@ -40,6 +40,7 @@ inline void ActorInfo::init(int32 sched_id, Slice name, ObjectPool<ActorInfo>::O
if (!is_lite) {
context_ = Scheduler::context()->this_ptr_.lock();
VLOG(actor) << "Set context " << context_.get() << " for " << name;
#ifdef TD_DEBUG
name_ = name.str();
#endif
@ -77,6 +78,7 @@ inline void ActorInfo::clear() {
// NB: must be in non migrating state
// store invalid scheduler id.
sched_id_.store((1 << 30) - 1, std::memory_order_relaxed);
VLOG(actor) << "Clear context " << context_.get() << " for " << get_name();
context_.reset();
}

View File

@ -124,7 +124,7 @@ int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
int err = X509_STORE_CTX_get_error(ctx);
auto warning = PSTRING() << "verify error:num=" << err << ":" << X509_verify_cert_error_string(err)
<< ":depth=" << X509_STORE_CTX_get_error_depth(ctx) << ":" << buf;
<< ":depth=" << X509_STORE_CTX_get_error_depth(ctx) << ":" << Slice(buf, std::strlen(buf));
double now = Time::now();
static std::mutex warning_mutex;

View File

@ -174,7 +174,7 @@ inline StringBuilder &operator<<(StringBuilder &logger, Time t) {
while (i + 1 < durations_n && t.seconds_ > 10 * durations[i + 1].value) {
i++;
}
logger << StringBuilder::FixedDouble(t.seconds_ / durations[i].value, 1) << durations[i].name;
logger << StringBuilder::FixedDouble(t.seconds_ / durations[i].value, 1) << Slice(durations[i].name);
return logger;
}
@ -200,7 +200,7 @@ inline StringBuilder &operator<<(StringBuilder &logger, Size t) {
while (i + 1 < sizes_n && t.size_ > 10 * sizes[i + 1].value) {
i++;
}
logger << t.size_ / sizes[i].value << sizes[i].name;
logger << t.size_ / sizes[i].value << Slice(sizes[i].name);
return logger;
}

View File

@ -251,7 +251,7 @@ class Logger {
Logger(LogInterface &log, const LogOptions &options, int log_level, Slice file_name, int line_num, Slice comment);
template <class T>
Logger &operator<<(const T &other) {
Logger &operator<<(T &&other) {
sb_ << other;
return *this;
}

View File

@ -112,7 +112,7 @@ void Epoll::run(int timeout_ms) {
flags = flags | PollFlags::Error();
}
if (event->events) {
LOG(FATAL) << "Unsupported epoll events: " << event->events;
LOG(FATAL) << "Unsupported epoll events: " << static_cast<int32>(event->events);
}
//LOG(DEBUG) << "Epoll event " << tag("fd", event->data.fd) << tag("flags", format::as_binary(flags));
auto pollable_fd = PollableFd::from_list_node(static_cast<ListNode *>(event->data.ptr));

View File

@ -77,7 +77,7 @@ void EventFdBsd::release() {
}
size_t size = result.ok();
if (size != sizeof(value)) {
LOG(FATAL) << "EventFdBsd write returned " << value << " instead of " << sizeof(value);
LOG(FATAL) << "EventFdBsd write returned " << size << " instead of " << sizeof(value);
}
}

View File

@ -16,6 +16,8 @@
#if TD_PORT_POSIX
#include <cstring>
#if TD_ANDROID
#include <sys/system_properties.h>
#else
@ -99,7 +101,8 @@ Slice get_operating_system_version() {
utsname name;
int err = uname(&name);
if (err == 0) {
auto os_name = trim(PSTRING() << name.sysname << " " << name.release);
auto os_name = trim(PSTRING() << Slice(name.sysname, std::strlen(name.sysname)) << " "
<< Slice(name.release, std::strlen(name.release)));
if (!os_name.empty()) {
return os_name;
}

View File

@ -177,6 +177,7 @@ class messages_sendEncryptedService final {
class messages_sendEncrypted final {
public:
int32 flags_;
tl_object_ptr<inputEncryptedChat> peer_;
int64 random_id_{};
BufferSlice data_;
@ -185,7 +186,8 @@ class messages_sendEncrypted final {
static const int32 ID = -1451792525;
explicit messages_sendEncrypted(TlBufferParser &p)
: peer_(TlFetchBoxed<TlFetchObject<inputEncryptedChat>, -247351839>::parse(p))
: flags_(TlFetchInt::parse(p))
, peer_(TlFetchBoxed<TlFetchObject<inputEncryptedChat>, -247351839>::parse(p))
, random_id_(TlFetchLong::parse(p))
, data_(TlFetchBytes<BufferSlice>::parse(p)) {
}