Update layer 75:

- Add connected websites support.
- Add flag supports_streaming to video and inputMessageVideo.
- Add new methods for message loading: getRepliedMessage and
  getChatPinnedMessage.

GitOrigin-RevId: 1dc5d367e27722fe9c8d2765f62ed80176eea2ce
This commit is contained in:
levlam 2018-02-07 02:31:38 +03:00
parent ee59648564
commit 154022ebfe
21 changed files with 490 additions and 74 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
project(TDLib VERSION 1.1.1 LANGUAGES CXX C)
project(TDLib VERSION 1.1.2 LANGUAGES CXX C)
option(TD_ENABLE_JNI "Use \"ON\" to enable JNI-compatible TDLib API.")

View File

@ -104,7 +104,7 @@ target_link_libraries(YourTarget PRIVATE Td::TdStatic)
Or you could install `TDLib` and then reference it in your CMakeLists.txt like this:
```
find_package(Td 1.1.1 REQUIRED)
find_package(Td 1.1.2 REQUIRED)
target_link_libraries(YourTarget PRIVATE Td::TdStatic)
```
See [example/cpp/CMakeLists.txt](https://github.com/tdlib/td/tree/master/example/cpp/CMakeLists.txt).

View File

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

View File

@ -203,8 +203,9 @@ photo id:int64 has_stickers:Bool sizes:vector<photoSize> = Photo;
sticker set_id:int64 width:int32 height:int32 emoji:string is_mask:Bool mask_position:maskPosition thumbnail:photoSize sticker:file = Sticker;
//@description Describes a video file @duration Duration of the video, in seconds; as defined by the sender @width Video width; as defined by the sender @height Video height; as defined by the sender
//@file_name Original name of the file; as defined by the sender @mime_type MIME type of the file; as defined by the sender @has_stickers True, if stickers were added to the photo @thumbnail Video thumbnail; as defined by the sender; may be null @video File containing the video
video duration:int32 width:int32 height:int32 file_name:string mime_type:string has_stickers:Bool thumbnail:photoSize video:file = Video;
//@file_name Original name of the file; as defined by the sender @mime_type MIME type of the file; as defined by the sender @has_stickers True, if stickers were added to the photo
//@supports_streaming True, if the video should be tried to streamed @thumbnail Video thumbnail; as defined by the sender; may be null @video File containing the video
video duration:int32 width:int32 height:int32 file_name:string mime_type:string has_stickers:Bool supports_streaming:Bool thumbnail:photoSize video:file = Video;
//@description Describes a video note. The video must be equal in width and height, cropped to a circle, and stored in MPEG4 format @duration Duration of the video, in seconds; as defined by the sender @length Video width and height; as defined by the sender @thumbnail Video thumbnail; as defined by the sender; may be null @video File containing the video
videoNote duration:int32 length:int32 thumbnail:photoSize video:file = VideoNote;
@ -977,9 +978,10 @@ inputMessagePhoto photo:InputFile thumbnail:inputThumbnail added_sticker_file_id
//@description A sticker message @sticker Sticker to be sent @thumbnail Sticker thumbnail, if available @width Sticker width @height Sticker height
inputMessageSticker sticker:InputFile thumbnail:inputThumbnail width:int32 height:int32 = InputMessageContent;
//@description A video message @video Video to be sent @thumbnail Video thumbnail, if available @added_sticker_file_ids File identifiers of the stickers added to the video, if applicable @duration Duration of the video, in seconds @width Video width @height Video height @caption Video caption; 0-200 characters
//@ttl Video TTL (Time To Live), in seconds (0-60). A non-zero TTL can be specified only in private chats
inputMessageVideo video:InputFile thumbnail:inputThumbnail added_sticker_file_ids:vector<int32> duration:int32 width:int32 height:int32 caption:formattedText ttl:int32 = InputMessageContent;
//@description A video message @video Video to be sent @thumbnail Video thumbnail, if available @added_sticker_file_ids File identifiers of the stickers added to the video, if applicable
//@duration Duration of the video, in seconds @width Video width @height Video height @supports_streaming True, if the video should be tried to streamed
//@caption Video caption; 0-200 characters @ttl Video TTL (Time To Live), in seconds (0-60). A non-zero TTL can be specified only in private chats
inputMessageVideo video:InputFile thumbnail:inputThumbnail added_sticker_file_ids:vector<int32> duration:int32 width:int32 height:int32 supports_streaming:Bool caption:formattedText ttl:int32 = InputMessageContent;
//@description A video note message @video_note Video note to be sent @thumbnail Video thumbnail, if available @duration Duration of the video, in seconds @length Video width and height; must be positive and not greater than 640
inputMessageVideoNote video_note:InputFile thumbnail:inputThumbnail duration:int32 length:int32 = InputMessageContent;
@ -1512,9 +1514,12 @@ userPrivacySettingAllowCalls = UserPrivacySetting;
accountTtl days:int32 = AccountTtl;
//@description Contains information about one session in a Telegram application used by the current user @id Session identifier @is_current True, if this session is the current session @api_id Telegram API identifier, as provided by the application @application_name Name of the application, as provided by the application
//@application_version The version of the application, as provided by the application @is_official_application True, if the application is an official application or uses the api_id of an official application @device_model Model of the device the application has been run or is running on, as provided by the application @platform Operating system the application has been run or is running on, as provided by the application
//@system_version Version of the operating system the application has been run or is running on, as provided by the application @log_in_date Point in time (Unix timestamp) when the user has logged in @last_active_date Point in time (Unix timestamp) when the session was last used @ip IP address from which the session was created, in human-readable format
//@description Contains information about one session in a Telegram application used by the current user @id Session identifier @is_current True, if this session is the current session
//@api_id Telegram API identifier, as provided by the application @application_name Name of the application, as provided by the application
//@application_version The version of the application, as provided by the application @is_official_application True, if the application is an official application or uses the api_id of an official application
//@device_model Model of the device the application has been run or is running on, as provided by the application @platform Operating system the application has been run or is running on, as provided by the application
//@system_version Version of the operating system the application has been run or is running on, as provided by the application @log_in_date Point in time (Unix timestamp) when the user has logged in
//@last_active_date Point in time (Unix timestamp) when the session was last used @ip IP address from which the session was created, in human-readable format
//@country A two-letter country code for the country from which the session was created, based on the IP address @region Region code from which the session was created, based on the IP address
session id:int64 is_current:Bool api_id:int32 application_name:string application_version:string is_official_application:Bool device_model:string platform:string system_version:string log_in_date:int32 last_active_date:int32 ip:string country:string region:string = Session;
@ -1522,6 +1527,22 @@ session id:int64 is_current:Bool api_id:int32 application_name:string applicatio
sessions sessions:vector<session> = Sessions;
//@description Contains information about one website the current user is logged in with Telegram
//@id Website identifier
//@domain_name The domain name of the website
//@bot_user_id User identifier of a bot linked with the website
//@browser The version of a browser used to log in
//@platform Operating system the browser is running on
//@log_in_date Point in time (Unix timestamp) when the user was logged in
//@last_active_date Point in time (Unix timestamp) when obtained authorization was last used
//@ip IP address from which the user was logged in, in human-readable format
//@location Human-readable description of a country and a region, from which the user was logged in, based on the IP address
connectedWebsite id:int64 domain_name:string bot_user_id:int32 browser:string platform:string log_in_date:int32 last_active_date:int32 ip:string location:string = ConnectedWebsite;
//@description Contains a list of websites the current user is logged in with Telegram @websites List of connected websites
connectedWebsites websites:vector<connectedWebsite> = ConnectedWebsites;
//@description Contains information about the availability of the "Report spam" action for a chat @can_report_spam True, if a prompt with the "Report spam" action should be shown to the user
chatReportSpamState can_report_spam:Bool = ChatReportSpamState;
@ -2022,6 +2043,12 @@ getChat chat_id:int53 = Chat;
//@description Returns information about a message @chat_id Identifier of the chat the message belongs to @message_id Identifier of the message to get
getMessage chat_id:int53 message_id:int53 = Message;
//@description Returns information about a message that is replied by given message @chat_id Identifier of the chat the message belongs to @message_id Identifier of the message reply to which get
getRepliedMessage chat_id:int53 message_id:int53 = Message;
//@description Returns information about a pinned chat message @chat_id Identifier of the chat the message belongs to
getChatPinnedMessage chat_id:int53 = Message;
//@description Returns information about messages. If a message is not found, returns null on the corresponding position of the result @chat_id Identifier of the chat the messages belong to @message_ids Identifiers of the messages to get
getMessages chat_id:int53 message_ids:vector<int53> = Messages;
@ -2561,6 +2588,16 @@ terminateSession session_id:int64 = Ok;
terminateAllOtherSessions = Ok;
//@description Returns all website where the current user used Telegram to log in
getConnectedWebsites = ConnectedWebsites;
//@description Disconnects website from the current user's Telegram account @website_id Website identifier
disconnectWebsite website_id:int64 = Ok;
//@description Disconnects all websites from the current user's Telegram account
disconnectAllWebsites = Ok;
//@description Toggles the "All members are admins" setting in basic groups; requires creator privileges in the group @basic_group_id Identifier of the basic group @everyone_is_administrator New value of everyone_is_administrator
toggleBasicGroupAdministrators basic_group_id:int32 everyone_is_administrator:Bool = Ok;

Binary file not shown.

View File

@ -438,7 +438,7 @@ accountDaysTTL#b8d0afdf days:int = AccountDaysTTL;
documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute;
documentAttributeAnimated#11b58939 = DocumentAttribute;
documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute;
documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true duration:int w:int h:int = DocumentAttribute;
documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true supports_streaming:flags.1?true duration:int w:int h:int = DocumentAttribute;
documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute;
documentAttributeFilename#15590068 file_name:string = DocumentAttribute;
documentAttributeHasStickers#9801d2f7 = DocumentAttribute;
@ -822,6 +822,14 @@ help.recentMeUrls#e0310d7 urls:Vector<RecentMeUrl> chats:Vector<Chat> users:Vect
inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector<MessageEntity> = InputSingleMedia;
webAuthorization#cac943f2 hash:long bot_id:int domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization;
account.webAuthorizations#ed56c9fc authorizations:Vector<WebAuthorization> users:Vector<User> = account.WebAuthorizations;
inputMessageID#a676a322 id:int = InputMessage;
inputMessageReplyTo#bad88395 id:int = InputMessage;
inputMessagePinned#86872538 = InputMessage;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@ -875,6 +883,9 @@ account.updatePasswordSettings#fa7c4b86 current_password_hash:bytes new_settings
account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode;
account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool;
account.getTmpPassword#4a82327e password_hash:bytes period:int = account.TmpPassword;
account.getWebAuthorizations#182e6d6f = account.WebAuthorizations;
account.resetWebAuthorization#2d01b9ef hash:long = Bool;
account.resetWebAuthorizations#682d2594 = Bool;
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
@ -895,7 +906,7 @@ contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.
contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool;
contacts.resetSaved#879537f1 = Bool;
messages.getMessages#4222fa74 id:Vector<int> = messages.Messages;
messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages;
messages.getDialogs#191ba9c5 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit: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#39e9ea0 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 = messages.Messages;
@ -1023,7 +1034,7 @@ channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages;
channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory;
channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector<int> = Bool;
channels.getMessages#93d7b347 channel:InputChannel id:Vector<int> = messages.Messages;
channels.getMessages#ad8c9a23 channel:InputChannel id:Vector<InputMessage> = messages.Messages;
channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants;
channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant;
channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;

Binary file not shown.

View File

@ -281,7 +281,8 @@ tl_object_ptr<telegram_api::InputMedia> AnimationsManager::get_input_media(
string mime_type = animation->mime_type;
if (animation->mime_type == "video/mp4") {
attributes.push_back(make_tl_object<telegram_api::documentAttributeVideo>(
0, false /*ignored*/, animation->duration, animation->dimensions.width, animation->dimensions.height));
0, false /*ignored*/, false /*ignored*/, animation->duration, animation->dimensions.width,
animation->dimensions.height));
} else if (animation->dimensions.width != 0 && animation->dimensions.height != 0) {
if (!begins_with(mime_type, "image/")) {
mime_type = "image/gif";

View File

@ -191,7 +191,7 @@ class ResetAuthorizationsQuery : public Td::ResultHandler {
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::account_resetAuthorization>(packet);
auto result_ptr = fetch_result<telegram_api::auth_resetAuthorizations>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
@ -206,6 +206,108 @@ class ResetAuthorizationsQuery : public Td::ResultHandler {
}
};
class GetWebAuthorizationsQuery : public Td::ResultHandler {
Promise<tl_object_ptr<td_api::connectedWebsites>> promise_;
public:
explicit GetWebAuthorizationsQuery(Promise<tl_object_ptr<td_api::connectedWebsites>> &&promise)
: promise_(std::move(promise)) {
}
void send() {
send_query(G()->net_query_creator().create(create_storer(telegram_api::account_getWebAuthorizations())));
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::account_getWebAuthorizations>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for GetWebAuthorizationsQuery: " << to_string(ptr);
td->contacts_manager_->on_get_users(std::move(ptr->users_));
auto results = make_tl_object<td_api::connectedWebsites>();
results->websites_.reserve(ptr->authorizations_.size());
for (auto &authorization : ptr->authorizations_) {
CHECK(authorization != nullptr);
UserId bot_user_id(authorization->bot_id_);
if (!bot_user_id.is_valid()) {
LOG(ERROR) << "Receive invalid bot " << bot_user_id;
bot_user_id = UserId();
}
results->websites_.push_back(make_tl_object<td_api::connectedWebsite>(
authorization->hash_, authorization->domain_,
td->contacts_manager_->get_user_id_object(bot_user_id, "GetWebAuthorizationsQuery"), authorization->browser_,
authorization->platform_, authorization->date_created_, authorization->date_active_, authorization->ip_,
authorization->region_));
}
promise_.set_value(std::move(results));
}
void on_error(uint64 id, Status status) override {
promise_.set_error(std::move(status));
}
};
class ResetWebAuthorizationQuery : public Td::ResultHandler {
Promise<Unit> promise_;
public:
explicit ResetWebAuthorizationQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(int64 hash) {
send_query(G()->net_query_creator().create(create_storer(telegram_api::account_resetWebAuthorization(hash))));
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::account_resetWebAuthorization>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
bool result = result_ptr.move_as_ok();
LOG_IF(WARNING, !result) << "Failed to disconnect website";
promise_.set_value(Unit());
}
void on_error(uint64 id, Status status) override {
promise_.set_error(std::move(status));
}
};
class ResetWebAuthorizationsQuery : public Td::ResultHandler {
Promise<Unit> promise_;
public:
explicit ResetWebAuthorizationsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send() {
send_query(G()->net_query_creator().create(create_storer(telegram_api::account_resetWebAuthorizations())));
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::account_resetWebAuthorizations>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
bool result = result_ptr.move_as_ok();
LOG_IF(WARNING, !result) << "Failed to disconnect all websites";
promise_.set_value(Unit());
}
void on_error(uint64 id, Status status) override {
promise_.set_error(std::move(status));
}
};
class BlockUserQuery : public Td::ResultHandler {
public:
void send(tl_object_ptr<telegram_api::InputUser> &&user) {
@ -2930,6 +3032,18 @@ void ContactsManager::terminate_all_other_sessions(Promise<Unit> &&promise) cons
td_->create_handler<ResetAuthorizationsQuery>(std::move(promise))->send();
}
void ContactsManager::get_connected_websites(Promise<tl_object_ptr<td_api::connectedWebsites>> &&promise) const {
td_->create_handler<GetWebAuthorizationsQuery>(std::move(promise))->send();
}
void ContactsManager::disconnect_website(int64 website_id, Promise<Unit> &&promise) const {
td_->create_handler<ResetWebAuthorizationQuery>(std::move(promise))->send(website_id);
}
void ContactsManager::disconnect_all_websites(Promise<Unit> &&promise) const {
td_->create_handler<ResetWebAuthorizationsQuery>(std::move(promise))->send();
}
Status ContactsManager::block_user(UserId user_id) {
if (user_id == get_my_id("block_user")) {
return Status::Error(5, "Can't block self");
@ -4108,6 +4222,14 @@ string ContactsManager::get_channel_invite_link(ChannelId channel_id) const {
return channel_full->invite_link;
}
MessageId ContactsManager::get_channel_pinned_message_id(ChannelId channel_id) const {
auto channel_full = get_channel_full(channel_id);
if (channel_full == nullptr) {
return MessageId();
}
return channel_full->pinned_message_id;
}
void ContactsManager::delete_chat_participant(ChatId chat_id, UserId user_id, Promise<Unit> &&promise) {
const Chat *c = get_chat(chat_id);
if (c == nullptr) {

View File

@ -213,6 +213,10 @@ class ContactsManager : public Actor {
void terminate_session(int64 session_id, Promise<Unit> &&promise) const;
void terminate_all_other_sessions(Promise<Unit> &&promise) const;
void get_connected_websites(Promise<tl_object_ptr<td_api::connectedWebsites>> &&promise) const;
void disconnect_website(int64 authorizations_id, Promise<Unit> &&promise) const;
void disconnect_all_websites(Promise<Unit> &&promise) const;
Status block_user(UserId user_id);
Status unblock_user(UserId user_id);
@ -302,6 +306,8 @@ class ContactsManager : public Actor {
string get_channel_invite_link(ChannelId channel_id) const;
MessageId get_channel_pinned_message_id(ChannelId channel_id) const;
ChannelId migrate_chat_to_megagroup(ChatId chat_id, Promise<Unit> &promise);
vector<DialogId> get_created_public_dialogs(Promise<Unit> &&promise);

View File

@ -124,6 +124,7 @@ std::pair<DocumentsManager::DocumentType, FileId> DocumentsManager::on_get_docum
auto document_type = DocumentType::General;
FileType file_type = FileType::Document;
Slice default_extension;
bool supports_streaming = false;
if (type_attributes == 1) { // not a general document
if (animated != nullptr) {
document_type = DocumentType::Animation;
@ -154,6 +155,7 @@ std::pair<DocumentsManager::DocumentType, FileId> DocumentsManager::on_get_docum
} else {
document_type = DocumentType::Video;
file_type = FileType::Video;
supports_streaming = (video->flags_ & telegram_api::documentAttributeVideo::SUPPORTS_STREAMING_MASK) != 0;
}
default_extension = "mp4";
}
@ -260,7 +262,8 @@ std::pair<DocumentsManager::DocumentType, FileId> DocumentsManager::on_get_docum
break;
case DocumentType::Video:
td_->videos_manager_->create_video(file_id, std::move(thumbnail), has_stickers, vector<FileId>(),
std::move(file_name), std::move(mime_type), video_duration, dimensions, true);
std::move(file_name), std::move(mime_type), video_duration, dimensions,
supports_streaming, true);
break;
case DocumentType::VideoNote:
td_->video_notes_manager_->create_video_note(file_id, std::move(thumbnail), video_duration, dimensions, true);

View File

@ -1022,7 +1022,8 @@ tl_object_ptr<td_api::sticker> copy(const td_api::sticker &obj) {
template <>
tl_object_ptr<td_api::video> copy(const td_api::video &obj) {
return make_tl_object<td_api::video>(obj.duration_, obj.width_, obj.height_, obj.file_name_, obj.mime_type_,
obj.has_stickers_, copy(obj.thumbnail_), copy(obj.video_));
obj.has_stickers_, obj.supports_streaming_, copy(obj.thumbnail_),
copy(obj.video_));
}
template <>
@ -1561,7 +1562,7 @@ void InlineQueriesManager::on_get_inline_query_results(UserId bot_user_id, uint6
auto video = make_tl_object<td_api::inlineQueryResultVideo>();
video->id_ = std::move(result->id_);
td_->videos_manager_->create_video(file_id, std::move(thumbnail), false, {}, std::move(file_name),
std::move(result->content_type_), duration, dimensions, false);
std::move(result->content_type_), duration, dimensions, false, false);
video->video_ = td_->videos_manager_->get_video_object(file_id);
video->title_ = std::move(result->title_);
video->description_ = std::move(result->description_);

View File

@ -248,9 +248,9 @@ class GetMessagesQuery : public Td::ResultHandler {
explicit GetMessagesQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(vector<MessageId> &&message_ids) {
send_query(G()->net_query_creator().create(
create_storer(telegram_api::messages_getMessages(MessagesManager::get_server_message_ids(message_ids)))));
void send(vector<tl_object_ptr<telegram_api::InputMessage>> &&message_ids) {
send_query(
G()->net_query_creator().create(create_storer(telegram_api::messages_getMessages(std::move(message_ids)))));
}
void on_result(uint64 id, BufferSlice packet) override {
@ -313,11 +313,11 @@ class GetChannelMessagesQuery : public Td::ResultHandler {
}
void send(ChannelId channel_id, tl_object_ptr<telegram_api::InputChannel> &&input_channel,
vector<MessageId> &&message_ids) {
vector<tl_object_ptr<telegram_api::InputMessage>> &&message_ids) {
channel_id_ = channel_id;
CHECK(input_channel != nullptr);
send_query(G()->net_query_creator().create(create_storer(telegram_api::channels_getMessages(
std::move(input_channel), MessagesManager::get_server_message_ids(message_ids)))));
send_query(G()->net_query_creator().create(
create_storer(telegram_api::channels_getMessages(std::move(input_channel), std::move(message_ids)))));
}
void on_result(uint64 id, BufferSlice packet) override {
@ -4671,12 +4671,11 @@ vector<MessageId> MessagesManager::get_message_ids(const vector<int64> &input_me
}
vector<int32> MessagesManager::get_server_message_ids(const vector<MessageId> &message_ids) {
vector<int32> server_message_ids;
server_message_ids.reserve(message_ids.size());
for (auto &message_id : message_ids) {
server_message_ids.push_back(message_id.get_server_message_id().get());
}
return server_message_ids;
return transform(message_ids, [](MessageId message_id) { return message_id.get_server_message_id().get(); });
}
tl_object_ptr<telegram_api::InputMessage> MessagesManager::get_input_message(MessageId message_id) {
return make_tl_object<telegram_api::inputMessageID>(message_id.get_server_message_id().get());
}
tl_object_ptr<telegram_api::InputPeer> MessagesManager::get_input_peer(DialogId dialog_id,
@ -10890,39 +10889,103 @@ MessagesManager::Message *MessagesManager::get_message_force(FullMessageId full_
return get_message_force(d, full_message_id.get_message_id());
}
bool MessagesManager::get_message(FullMessageId full_message_id, Promise<Unit> &&promise) {
Dialog *d = get_dialog_force(full_message_id.get_dialog_id());
if (d == nullptr) {
promise.set_error(Status::Error(6, "Chat not found"));
return false;
MessageId MessagesManager::get_replied_message_id(const Message *m) {
switch (m->content->get_id()) {
case MessagePinMessage::ID:
CHECK(!m->reply_to_message_id.is_valid());
return static_cast<const MessagePinMessage *>(m->content.get())->message_id;
case MessageGameScore::ID:
CHECK(!m->reply_to_message_id.is_valid());
return static_cast<const MessageGameScore *>(m->content.get())->game_message_id;
case MessagePaymentSuccessful::ID:
CHECK(!m->reply_to_message_id.is_valid());
return static_cast<const MessagePaymentSuccessful *>(m->content.get())->invoice_message_id;
default:
return m->reply_to_message_id;
}
}
auto message_id = full_message_id.get_message_id();
auto message = get_message_force(d, message_id);
if (message == nullptr && message_id.is_valid() && message_id.is_server()) {
void MessagesManager::get_message_force_from_server(Dialog *d, MessageId message_id, Promise<Unit> &&promise) {
auto m = get_message_force(d, message_id);
if (m == nullptr && message_id.is_valid() && message_id.is_server()) {
auto dialog_type = d->dialog_id.get_type();
if (d->last_new_message_id != MessageId() && message_id.get() > d->last_new_message_id.get()) {
// message will not be added to the dialog anyway
if (d->dialog_id.get_type() == DialogType::Channel) {
if (dialog_type == DialogType::Channel) {
// so we try to force channel difference first
postponed_get_message_requests_[d->dialog_id].emplace_back(message_id, std::move(promise));
get_channel_difference(d->dialog_id, d->pts, true, "get_message");
} else {
promise.set_value(Unit());
}
return false;
return;
}
if (d->deleted_message_ids.count(message_id)) {
promise.set_value(Unit());
return false;
if (d->deleted_message_ids.count(message_id) == 0 && dialog_type != DialogType::SecretChat) {
return get_messages_from_server({FullMessageId(d->dialog_id, message_id)}, std::move(promise));
}
get_messages_from_server({full_message_id}, std::move(promise));
return false;
}
promise.set_value(Unit());
return true;
}
void MessagesManager::get_message(FullMessageId full_message_id, Promise<Unit> &&promise) {
Dialog *d = get_dialog_force(full_message_id.get_dialog_id());
if (d == nullptr) {
return promise.set_error(Status::Error(6, "Chat not found"));
}
get_message_force_from_server(d, full_message_id.get_message_id(), std::move(promise));
}
MessageId MessagesManager::get_replied_message(DialogId dialog_id, MessageId message_id, bool force,
Promise<Unit> &&promise) {
Dialog *d = get_dialog_force(dialog_id);
if (d == nullptr) {
promise.set_error(Status::Error(6, "Chat not found"));
return MessageId();
}
auto m = get_message_force(d, message_id);
if (m == nullptr) {
if (force) {
promise.set_value(Unit());
} else {
get_message_force_from_server(d, message_id, std::move(promise));
}
return MessageId();
}
auto replied_message_id = get_replied_message_id(m);
get_message_force_from_server(d, replied_message_id, std::move(promise));
return replied_message_id;
}
MessageId MessagesManager::get_dialog_pinned_message(DialogId dialog_id, bool force, Promise<Unit> &&promise) {
Dialog *d = get_dialog_force(dialog_id);
if (d == nullptr) {
promise.set_error(Status::Error(6, "Chat not found"));
return MessageId();
}
if (dialog_id.get_type() != DialogType::Channel) {
promise.set_value(Unit());
return MessageId();
}
auto channel_id = dialog_id.get_channel_id();
auto message_id = td_->contacts_manager_->get_channel_pinned_message_id(channel_id);
if (!message_id.is_valid()) {
if (force) {
promise.set_value(Unit());
} else {
td_->contacts_manager_->get_channel_full(channel_id, std::move(promise));
}
return MessageId();
}
get_message_force_from_server(d, message_id, std::move(promise));
return message_id;
}
bool MessagesManager::get_messages(DialogId dialog_id, const vector<MessageId> &message_ids, Promise<Unit> &&promise) {
@ -10932,6 +10995,7 @@ bool MessagesManager::get_messages(DialogId dialog_id, const vector<MessageId> &
return false;
}
bool is_secret = dialog_id.get_type() == DialogType::SecretChat;
vector<FullMessageId> missed_message_ids;
for (auto message_id : message_ids) {
if (!message_id.is_valid()) {
@ -10940,11 +11004,9 @@ bool MessagesManager::get_messages(DialogId dialog_id, const vector<MessageId> &
}
auto message = get_message_force(d, message_id);
if (message == nullptr) {
if (message_id.is_server()) {
missed_message_ids.emplace_back(dialog_id, message_id);
continue;
}
if (message == nullptr && message_id.is_server() && !is_secret) {
missed_message_ids.emplace_back(dialog_id, message_id);
continue;
}
}
@ -10962,8 +11024,8 @@ void MessagesManager::get_messages_from_server(vector<FullMessageId> &&message_i
LOG(ERROR) << "Empty message_ids";
return;
}
vector<MessageId> ordinary_message_ids;
std::unordered_map<ChannelId, vector<MessageId>, ChannelIdHash> channel_message_ids;
vector<tl_object_ptr<telegram_api::InputMessage>> ordinary_message_ids;
std::unordered_map<ChannelId, vector<tl_object_ptr<telegram_api::InputMessage>>, ChannelIdHash> channel_message_ids;
for (auto &full_message_id : message_ids) {
auto dialog_id = full_message_id.get_dialog_id();
auto message_id = full_message_id.get_message_id();
@ -10974,10 +11036,10 @@ void MessagesManager::get_messages_from_server(vector<FullMessageId> &&message_i
switch (dialog_id.get_type()) {
case DialogType::User:
case DialogType::Chat:
ordinary_message_ids.push_back(message_id);
ordinary_message_ids.push_back(get_input_message(message_id));
break;
case DialogType::Channel:
channel_message_ids[dialog_id.get_channel_id()].push_back(message_id);
channel_message_ids[dialog_id.get_channel_id()].push_back(get_input_message(message_id));
break;
case DialogType::SecretChat:
LOG(ERROR) << "Can't get secret chat message from server";
@ -15299,7 +15361,8 @@ Result<MessagesManager::InputMessageContent> MessagesManager::process_input_mess
bool has_stickers = !sticker_file_ids.empty();
td_->videos_manager_->create_video(file_id, thumbnail, has_stickers, std::move(sticker_file_ids),
std::move(file_name), std::move(mime_type), input_video->duration_,
get_dimensions(input_video->width_, input_video->height_), false);
get_dimensions(input_video->width_, input_video->height_),
input_video->supports_streaming_, false);
content = make_unique<MessageVideo>(file_id, std::move(caption));
break;
@ -19900,8 +19963,8 @@ static auto secret_to_telegram(secret_api::documentAttributeSticker &sticker) {
// documentAttributeVideo #5910cccb 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*/, video.duration_, video.w_,
video.h_);
return make_tl_object<telegram_api::documentAttributeVideo>(0, false /*ignored*/, false /*ignored*/, video.duration_,
video.w_, video.h_);
}
// documentAttributeFilename #15590068 file_name:string = DocumentAttribute;
@ -19918,7 +19981,7 @@ static auto secret_to_telegram(secret_api::documentAttributeVideo66 &video) {
(video.flags_ & secret_api::documentAttributeVideo66::ROUND_MESSAGE_MASK) != 0
? telegram_api::documentAttributeVideo::ROUND_MESSAGE_MASK
: 0,
video.round_message_, video.duration_, video.w_, video.h_);
video.round_message_, false, video.duration_, video.w_, video.h_);
}
static auto telegram_documentAttributeAudio(bool is_voice_note, int duration, string title, string performer,

View File

@ -815,11 +815,12 @@ class MessagesManager : public Actor {
MessagesManager &operator=(MessagesManager &&) = delete;
~MessagesManager() override;
static vector<MessageId> get_message_ids(const vector<int32> &input_message_ids);
static vector<MessageId> get_message_ids(const vector<int64> &input_message_ids);
static vector<int32> get_server_message_ids(const vector<MessageId> &message_ids);
static tl_object_ptr<telegram_api::InputMessage> get_input_message(MessageId message_id);
static MessageId get_message_id(const tl_object_ptr<telegram_api::Message> &message_ptr);
DialogId get_message_dialog_id(const tl_object_ptr<telegram_api::Message> &message_ptr) const;
@ -1100,7 +1101,11 @@ class MessagesManager : public Actor {
bool have_message(FullMessageId full_message_id);
bool get_message(FullMessageId full_message_id, Promise<Unit> &&promise);
void get_message(FullMessageId full_message_id, Promise<Unit> &&promise);
MessageId get_replied_message(DialogId dialog_id, MessageId message_id, bool force, Promise<Unit> &&promise);
MessageId get_dialog_pinned_message(DialogId dialog_id, bool force, Promise<Unit> &&promise);
bool get_messages(DialogId dialog_id, const vector<MessageId> &message_ids, Promise<Unit> &&promise);
@ -1797,6 +1802,8 @@ class MessagesManager : public Actor {
MessageId get_persistent_message_id(const Dialog *d, MessageId message_id) const;
static MessageId get_replied_message_id(const Message *m);
MessageId get_reply_to_message_id(Dialog *d, MessageId message_id);
bool can_set_game_score(DialogId dialog_id, const Message *m) const;
@ -2162,6 +2169,8 @@ class MessagesManager : public Actor {
Message *get_message_force(FullMessageId full_message_id);
void get_message_force_from_server(Dialog *d, MessageId message_id, Promise<Unit> &&promise);
Message *on_get_message_from_database(DialogId dialog_id, Dialog *d, const BufferSlice &value);
void get_dialog_message_by_date_from_server(const Dialog *d, int32 date, int64 random_id, bool after_database_search,

View File

@ -683,6 +683,55 @@ class TerminateAllOtherSessionsRequest : public RequestOnceActor {
}
};
class GetConnectedWebsitesRequest : public RequestActor<tl_object_ptr<td_api::connectedWebsites>> {
tl_object_ptr<td_api::connectedWebsites> connected_websites_;
void do_run(Promise<tl_object_ptr<td_api::connectedWebsites>> &&promise) override {
if (get_tries() < 2) {
promise.set_value(std::move(connected_websites_));
return;
}
td->contacts_manager_->get_connected_websites(std::move(promise));
}
void do_set_result(tl_object_ptr<td_api::connectedWebsites> &&result) override {
connected_websites_ = std::move(result);
}
void do_send_result() override {
CHECK(connected_websites_ != nullptr);
send_result(std::move(connected_websites_));
}
public:
GetConnectedWebsitesRequest(ActorShared<Td> td, uint64 request_id) : RequestActor(std::move(td), request_id) {
}
};
class DisconnectWebsiteRequest : public RequestOnceActor {
int64 website_id_;
void do_run(Promise<Unit> &&promise) override {
td->contacts_manager_->disconnect_website(website_id_, std::move(promise));
}
public:
DisconnectWebsiteRequest(ActorShared<Td> td, uint64 request_id, int64 website_id)
: RequestOnceActor(std::move(td), request_id), website_id_(website_id) {
}
};
class DisconnectAllWebsitesRequest : public RequestOnceActor {
void do_run(Promise<Unit> &&promise) override {
td->contacts_manager_->disconnect_all_websites(std::move(promise));
}
public:
DisconnectAllWebsitesRequest(ActorShared<Td> td, uint64 request_id) : RequestOnceActor(std::move(td), request_id) {
}
};
class GetUserRequest : public RequestActor<> {
UserId user_id_;
@ -985,6 +1034,49 @@ class GetMessageRequest : public RequestOnceActor {
}
};
class GetRepliedMessageRequest : public RequestOnceActor {
DialogId dialog_id_;
MessageId message_id_;
MessageId replied_message_id_;
void do_run(Promise<Unit> &&promise) override {
replied_message_id_ =
td->messages_manager_->get_replied_message(dialog_id_, message_id_, get_tries() < 3, std::move(promise));
}
void do_send_result() override {
send_result(td->messages_manager_->get_message_object({dialog_id_, replied_message_id_}));
}
public:
GetRepliedMessageRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, int64 message_id)
: RequestOnceActor(std::move(td), request_id), dialog_id_(dialog_id), message_id_(message_id) {
set_tries(3);
}
};
class GetChatPinnedMessageRequest : public RequestActor<> {
DialogId dialog_id_;
MessageId pinned_message_id_;
void do_run(Promise<Unit> &&promise) override {
pinned_message_id_ =
td->messages_manager_->get_dialog_pinned_message(dialog_id_, get_tries() < 3, std::move(promise));
}
void do_send_result() override {
send_result(td->messages_manager_->get_message_object({dialog_id_, pinned_message_id_}));
}
public:
GetChatPinnedMessageRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id)
: RequestActor<>(std::move(td), request_id), dialog_id_(dialog_id) {
set_tries(3);
}
};
class GetMessagesRequest : public RequestOnceActor {
DialogId dialog_id_;
vector<MessageId> message_ids_;
@ -4724,6 +4816,24 @@ void Td::on_request(uint64 id, const td_api::terminateAllOtherSessions &request)
CREATE_NO_ARGS_REQUEST(TerminateAllOtherSessionsRequest);
}
void Td::on_request(uint64 id, const td_api::getConnectedWebsites &request) {
CHECK_AUTH();
CHECK_IS_USER();
CREATE_NO_ARGS_REQUEST(GetConnectedWebsitesRequest);
}
void Td::on_request(uint64 id, const td_api::disconnectWebsite &request) {
CHECK_AUTH();
CHECK_IS_USER();
CREATE_REQUEST(DisconnectWebsiteRequest, request.website_id_);
}
void Td::on_request(uint64 id, const td_api::disconnectAllWebsites &request) {
CHECK_AUTH();
CHECK_IS_USER();
CREATE_NO_ARGS_REQUEST(DisconnectAllWebsitesRequest);
}
void Td::on_request(uint64 id, const td_api::getMe &) {
CHECK_AUTH();
@ -4777,6 +4887,16 @@ void Td::on_request(uint64 id, const td_api::getMessage &request) {
CREATE_REQUEST(GetMessageRequest, request.chat_id_, request.message_id_);
}
void Td::on_request(uint64 id, const td_api::getRepliedMessage &request) {
CHECK_AUTH();
CREATE_REQUEST(GetRepliedMessageRequest, request.chat_id_, request.message_id_);
}
void Td::on_request(uint64 id, const td_api::getChatPinnedMessage &request) {
CHECK_AUTH();
CREATE_REQUEST(GetChatPinnedMessageRequest, request.chat_id_);
}
void Td::on_request(uint64 id, const td_api::getMessages &request) {
CHECK_AUTH();
CREATE_REQUEST(GetMessagesRequest, request.chat_id_, request.message_ids_);

View File

@ -191,7 +191,7 @@ class Td final : public NetQueryCallback {
static td_api::object_ptr<td_api::Object> static_request(td_api::object_ptr<td_api::Function> function);
private:
static constexpr const char *tdlib_version = "1.1.1";
static constexpr const char *tdlib_version = "1.1.2";
static constexpr int32 ONLINE_TIMEOUT = 240;
void send_result(uint64 id, tl_object_ptr<td_api::Object> object);
@ -346,6 +346,12 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::terminateAllOtherSessions &request);
void on_request(uint64 id, const td_api::getConnectedWebsites &request);
void on_request(uint64 id, const td_api::disconnectWebsite &request);
void on_request(uint64 id, const td_api::disconnectAllWebsites &request);
void on_request(uint64 id, const td_api::getMe &request);
void on_request(uint64 id, const td_api::getUser &request);
@ -366,6 +372,10 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::getMessage &request);
void on_request(uint64 id, const td_api::getRepliedMessage &request);
void on_request(uint64 id, const td_api::getChatPinnedMessage &request);
void on_request(uint64 id, const td_api::getMessages &request);
void on_request(uint64 id, const td_api::getPublicMessageLink &request);

View File

@ -214,8 +214,8 @@ tl_object_ptr<telegram_api::InputMedia> VideoNotesManager::get_input_media(
vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes;
attributes.push_back(make_tl_object<telegram_api::documentAttributeVideo>(
telegram_api::documentAttributeVideo::ROUND_MESSAGE_MASK, false /*ignored*/, video_note->duration,
video_note->dimensions.width ? video_note->dimensions.width : 240,
telegram_api::documentAttributeVideo::ROUND_MESSAGE_MASK, false /*ignored*/, false /*ignored*/,
video_note->duration, video_note->dimensions.width ? video_note->dimensions.width : 240,
video_note->dimensions.height ? video_note->dimensions.height : 240));
int32 flags = 0;
if (input_thumbnail != nullptr) {

View File

@ -45,6 +45,7 @@ tl_object_ptr<td_api::video> VideosManager::get_video_object(FileId file_id) {
return make_tl_object<td_api::video>(video->duration, video->dimensions.width, video->dimensions.height,
video->file_name, video->mime_type, video->has_stickers,
video->supports_streaming,
get_photo_size_object(td_->file_manager_.get(), &video->thumbnail),
td_->file_manager_->get_file_object(video->file_id));
}
@ -62,10 +63,12 @@ FileId VideosManager::on_get_video(std::unique_ptr<Video> new_video, bool replac
v->mime_type = new_video->mime_type;
v->is_changed = true;
}
if (v->duration != new_video->duration || v->dimensions != new_video->dimensions) {
if (v->duration != new_video->duration || v->dimensions != new_video->dimensions ||
v->supports_streaming != new_video->supports_streaming) {
LOG(DEBUG) << "Video " << file_id << " info has changed";
v->duration = new_video->duration;
v->dimensions = new_video->dimensions;
v->supports_streaming = new_video->supports_streaming;
v->is_changed = true;
}
if (v->file_name != new_video->file_name) {
@ -173,7 +176,7 @@ bool VideosManager::merge_videos(FileId new_id, FileId old_id, bool can_delete_o
void VideosManager::create_video(FileId file_id, PhotoSize thumbnail, bool has_stickers,
vector<FileId> &&sticker_file_ids, string file_name, string mime_type, int32 duration,
Dimensions dimensions, bool replace) {
Dimensions dimensions, bool supports_streaming, bool replace) {
auto v = make_unique<Video>();
v->file_id = file_id;
v->file_name = std::move(file_name);
@ -181,6 +184,7 @@ void VideosManager::create_video(FileId file_id, PhotoSize thumbnail, bool has_s
v->duration = std::max(duration, 0);
v->dimensions = dimensions;
v->thumbnail = std::move(thumbnail);
v->supports_streaming = supports_streaming;
v->has_stickers = has_stickers;
v->sticker_file_ids = std::move(sticker_file_ids);
on_get_video(std::move(v), replace);
@ -245,9 +249,15 @@ tl_object_ptr<telegram_api::InputMedia> VideosManager::get_input_media(
const Video *video = get_video(file_id);
CHECK(video != nullptr);
int32 attribute_flags = 0;
if (video->supports_streaming) {
attribute_flags |= telegram_api::documentAttributeVideo::SUPPORTS_STREAMING_MASK;
}
vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes;
attributes.push_back(make_tl_object<telegram_api::documentAttributeVideo>(
0, false /*ignored*/, video->duration, video->dimensions.width, video->dimensions.height));
attribute_flags, false /*ignored*/, false /*ignored*/, video->duration, video->dimensions.width,
video->dimensions.height));
if (!video->file_name.empty()) {
attributes.push_back(make_tl_object<telegram_api::documentAttributeFilename>(video->file_name));
}

View File

@ -33,7 +33,8 @@ class VideosManager {
tl_object_ptr<td_api::video> get_video_object(FileId file_id);
void create_video(FileId file_id, PhotoSize thumbnail, bool has_stickers, vector<FileId> &&sticker_file_ids,
string file_name, string mime_type, int32 duration, Dimensions dimensions, bool replace);
string file_name, string mime_type, int32 duration, Dimensions dimensions, bool supports_streaming,
bool replace);
tl_object_ptr<telegram_api::InputMedia> get_input_media(FileId file_id,
tl_object_ptr<telegram_api::InputFile> input_file,
@ -69,6 +70,8 @@ class VideosManager {
Dimensions dimensions;
PhotoSize thumbnail;
bool supports_streaming = false;
bool has_stickers = false;
vector<FileId> sticker_file_ids;

View File

@ -22,6 +22,7 @@ void VideosManager::store_video(FileId file_id, T &storer) const {
const Video *video = it->second.get();
BEGIN_STORE_FLAGS();
STORE_FLAG(video->has_stickers);
STORE_FLAG(video->supports_streaming);
END_STORE_FLAGS();
store(video->file_name, storer);
store(video->mime_type, storer);
@ -39,6 +40,7 @@ FileId VideosManager::parse_video(T &parser) {
auto video = make_unique<Video>();
BEGIN_PARSE_FLAGS();
PARSE_FLAG(video->has_stickers);
PARSE_FLAG(video->supports_streaming);
END_PARSE_FLAGS();
parse(video->file_name, parser);
parse(video->mime_type, parser);

View File

@ -395,7 +395,11 @@ class CliClient final : public Actor {
}
static int64 as_message_id(Slice str) {
return to_integer<int64>(trim(str));
str = trim(str);
if (!str.empty() && str.back() == 's') {
return to_integer<int32>(str) << 20;
}
return to_integer<int64>(str);
}
static vector<int64> as_message_ids(Slice message_ids_string, char delimiter = ' ') {
@ -1479,6 +1483,12 @@ class CliClient final : public Actor {
send_request(make_tl_object<td_api::terminateSession>(to_integer<int64>(args)));
} else if (op == "TerminateAllOtherSessions") {
send_request(make_tl_object<td_api::terminateAllOtherSessions>());
} else if (op == "gcw") {
send_request(make_tl_object<td_api::getConnectedWebsites>());
} else if (op == "dw") {
send_request(make_tl_object<td_api::disconnectWebsite>(to_integer<int64>(args)));
} else if (op == "daw") {
send_request(make_tl_object<td_api::disconnectAllWebsites>());
} else if (op == "gw") {
send_request(make_tl_object<td_api::getWallpapers>());
} else if (op == "git") {
@ -1797,6 +1807,14 @@ class CliClient final : public Actor {
string message_id;
std::tie(chat_id, message_id) = split(args);
send_request(make_tl_object<td_api::getMessage>(as_chat_id(chat_id), as_message_id(message_id)));
} else if (op == "grm") {
string chat_id;
string message_id;
std::tie(chat_id, message_id) = split(args);
send_request(make_tl_object<td_api::getRepliedMessage>(as_chat_id(chat_id), as_message_id(message_id)));
} else if (op == "gcpm") {
string chat_id = args;
send_request(make_tl_object<td_api::getChatPinnedMessage>(as_chat_id(chat_id)));
} else if (op == "gms") {
string chat_id;
string message_ids;
@ -2408,9 +2426,9 @@ class CliClient final : public Actor {
sticker_file_ids = to_integers<int32>(sticker_file_ids_str, ',');
}
send_message(chat_id,
make_tl_object<td_api::inputMessageVideo>(as_local_file(video_path), nullptr,
std::move(sticker_file_ids), 1, 2, 3, as_caption(""), 0));
send_message(chat_id, make_tl_object<td_api::inputMessageVideo>(as_local_file(video_path), nullptr,
std::move(sticker_file_ids), 1, 2, 3, true,
as_caption(""), 0));
} else if (op == "svn") {
string chat_id;
string video_path;