diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ae7d7ae0..39a7fceca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -404,6 +404,7 @@ set(TDLIB_SOURCE td/telegram/Dependencies.cpp td/telegram/DeviceTokenManager.cpp td/telegram/DhCache.cpp + td/telegram/DialogAction.cpp td/telegram/DialogAdministrator.cpp td/telegram/DialogDb.cpp td/telegram/DialogFilter.cpp @@ -563,6 +564,7 @@ set(TDLIB_SOURCE td/telegram/DeviceTokenManager.h td/telegram/DhCache.h td/telegram/DhConfig.h + td/telegram/DialogAction.h td/telegram/DialogAdministrator.h td/telegram/DialogDate.h td/telegram/DialogDb.h @@ -836,7 +838,6 @@ if (TD_ENABLE_DOTNET) td/telegram/LogDotNet.cpp ${TL_DOTNET_SCHEME_SOURCE} ) - set(VCPKG_APPLOCAL_LIBRARY_DEPS ON) set_target_properties(tddotnet PROPERTIES OUTPUT_NAME Telegram.Td) target_link_libraries(tddotnet PRIVATE tdclient tdutils) target_include_directories(tddotnet PUBLIC diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 3ace46ff5..19a3ee477 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -639,15 +639,19 @@ 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), to the Replies bot chat, 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 message replies +//@reply_count Number of times the message was directly or indirectly replied +//@recent_replier_user_ids User identifiers of the recent repliers to the message; available in channels with a discussion supergroup +//@last_read_inbox_message_id Identifier of the last read incoming reply to the message +//@last_read_outbox_message_id Identifier of the last read outgoing reply to the message +//@last_message_id Identifier of the last reply to the message +messageReplyInfo reply_count:int32 recent_replier_user_ids:vector last_read_inbox_message_id:int53 last_read_outbox_message_id:int53 last_message_id:int53 = MessageReplyInfo; + //@description Contains information about interactions with a message //@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; available in discussion supergroups and channels with a discussion supergroup -//@recent_replier_user_ids User identifiers of the recent repliers to the message; available in channels with a discussion supergroup -//@last_read_inbox_comment_message_id Identifier of the last read incoming comment to the message -//@last_read_outbox_comment_message_id Identifier of the last read outgoing comment to the message -//@last_comment_message_id Identifier of the last comment to the message -messageInteractionInfo view_count:int32 forward_count:int32 reply_count:int32 recent_replier_user_ids:vector last_read_inbox_comment_message_id:int53 last_read_outbox_comment_message_id:int53 last_comment_message_id:int53 = MessageInteractionInfo; +//@reply_info Contains information about direct or indirect replies to the message; may be null. Currently, available only in channels with a discussion supergroup and discussion supergroups for messages, which are not replies itself +messageInteractionInfo view_count:int32 forward_count:int32 reply_info:messageReplyInfo = MessageInteractionInfo; //@class MessageSendingState @description Contains information about the sending state of the message diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index 6097739be..6db621573 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/DialogAction.cpp b/td/telegram/DialogAction.cpp new file mode 100644 index 000000000..6ec236332 --- /dev/null +++ b/td/telegram/DialogAction.cpp @@ -0,0 +1,376 @@ +// +// 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/DialogAction.h" + +namespace td { + +void DialogAction::init(Type type) { + type_ = type; + progress_ = 0; +} + +void DialogAction::init(Type type, int32 progress) { + if (progress < 0 || progress > 100) { + progress = 0; + } + type_ = type; + progress_ = progress; +} + +DialogAction::DialogAction(Type type, int32 progress) { + init(type, progress); +} + +DialogAction::DialogAction(tl_object_ptr &&action) { + if (action == nullptr) { + return; + } + + switch (action->get_id()) { + case td_api::chatActionCancel::ID: + init(Type::Cancel); + break; + case td_api::chatActionTyping::ID: + init(Type::Typing); + break; + case td_api::chatActionRecordingVideo::ID: + init(Type::RecordingVideo); + break; + case td_api::chatActionUploadingVideo::ID: { + auto uploading_action = move_tl_object_as(action); + init(Type::UploadingVideo, uploading_action->progress_); + break; + } + case td_api::chatActionRecordingVoiceNote::ID: + init(Type::RecordingVoiceNote); + break; + case td_api::chatActionUploadingVoiceNote::ID: { + auto uploading_action = move_tl_object_as(action); + init(Type::UploadingVoiceNote, uploading_action->progress_); + break; + } + case td_api::chatActionUploadingPhoto::ID: { + auto uploading_action = move_tl_object_as(action); + init(Type::UploadingPhoto, uploading_action->progress_); + break; + } + case td_api::chatActionUploadingDocument::ID: { + auto uploading_action = move_tl_object_as(action); + init(Type::UploadingDocument, uploading_action->progress_); + break; + } + case td_api::chatActionChoosingLocation::ID: + init(Type::ChoosingLocation); + break; + case td_api::chatActionChoosingContact::ID: + init(Type::ChoosingContact); + break; + case td_api::chatActionStartPlayingGame::ID: + init(Type::StartPlayingGame); + break; + case td_api::chatActionRecordingVideoNote::ID: + init(Type::RecordingVideoNote); + break; + case td_api::chatActionUploadingVideoNote::ID: { + auto uploading_action = move_tl_object_as(action); + init(Type::UploadingVideoNote, uploading_action->progress_); + break; + } + default: + UNREACHABLE(); + break; + } +} + +DialogAction::DialogAction(tl_object_ptr &&action) { + switch (action->get_id()) { + case telegram_api::sendMessageCancelAction::ID: + init(Type::Cancel); + break; + case telegram_api::sendMessageTypingAction::ID: + init(Type::Typing); + break; + case telegram_api::sendMessageRecordVideoAction::ID: + init(Type::RecordingVideo); + break; + case telegram_api::sendMessageUploadVideoAction::ID: { + auto upload_video_action = move_tl_object_as(action); + init(Type::UploadingVideo, upload_video_action->progress_); + break; + } + case telegram_api::sendMessageRecordAudioAction::ID: + init(Type::RecordingVoiceNote); + break; + case telegram_api::sendMessageUploadAudioAction::ID: { + auto upload_audio_action = move_tl_object_as(action); + init(Type::UploadingVoiceNote, upload_audio_action->progress_); + break; + } + case telegram_api::sendMessageUploadPhotoAction::ID: { + auto upload_photo_action = move_tl_object_as(action); + init(Type::UploadingPhoto, upload_photo_action->progress_); + break; + } + case telegram_api::sendMessageUploadDocumentAction::ID: { + auto upload_document_action = move_tl_object_as(action); + init(Type::UploadingDocument, upload_document_action->progress_); + break; + } + case telegram_api::sendMessageGeoLocationAction::ID: + init(Type::ChoosingLocation); + break; + case telegram_api::sendMessageChooseContactAction::ID: + init(Type::ChoosingContact); + break; + case telegram_api::sendMessageGamePlayAction::ID: + init(Type::StartPlayingGame); + break; + case telegram_api::sendMessageRecordRoundAction::ID: + init(Type::RecordingVideoNote); + break; + case telegram_api::sendMessageUploadRoundAction::ID: { + auto upload_round_action = move_tl_object_as(action); + init(Type::UploadingVideoNote, upload_round_action->progress_); + break; + } + default: + UNREACHABLE(); + break; + } +} + +tl_object_ptr DialogAction::get_input_send_message_action() const { + switch (type_) { + case Type::Cancel: + return make_tl_object(); + case Type::Typing: + return make_tl_object(); + case Type::RecordingVideo: + return make_tl_object(); + case Type::UploadingVideo: + return make_tl_object(progress_); + case Type::RecordingVoiceNote: + return make_tl_object(); + case Type::UploadingVoiceNote: + return make_tl_object(progress_); + case Type::UploadingPhoto: + return make_tl_object(progress_); + case Type::UploadingDocument: + return make_tl_object(progress_); + case Type::ChoosingLocation: + return make_tl_object(); + case Type::ChoosingContact: + return make_tl_object(); + case Type::RecordingVideoNote: + return make_tl_object(); + case Type::UploadingVideoNote: + return make_tl_object(progress_); + case Type::StartPlayingGame: + return make_tl_object(); + default: + UNREACHABLE(); + return nullptr; + } +} + +tl_object_ptr DialogAction::get_secret_input_send_message_action() const { + switch (type_) { + case Type::Cancel: + return make_tl_object(); + case Type::Typing: + return make_tl_object(); + case Type::RecordingVideo: + return make_tl_object(); + case Type::UploadingVideo: + return make_tl_object(); + case Type::RecordingVoiceNote: + return make_tl_object(); + case Type::UploadingVoiceNote: + return make_tl_object(); + case Type::UploadingPhoto: + return make_tl_object(); + case Type::UploadingDocument: + return make_tl_object(); + case Type::ChoosingLocation: + return make_tl_object(); + case Type::ChoosingContact: + return make_tl_object(); + case Type::RecordingVideoNote: + return make_tl_object(); + case Type::UploadingVideoNote: + return make_tl_object(); + case Type::StartPlayingGame: + return make_tl_object(); + default: + UNREACHABLE(); + return nullptr; + } +} + +tl_object_ptr DialogAction::get_chat_action_object() const { + switch (type_) { + case Type::Cancel: + return td_api::make_object(); + case Type::Typing: + return td_api::make_object(); + case Type::RecordingVideo: + return td_api::make_object(); + case Type::UploadingVideo: + return td_api::make_object(progress_); + case Type::RecordingVoiceNote: + return td_api::make_object(); + case Type::UploadingVoiceNote: + return td_api::make_object(progress_); + case Type::UploadingPhoto: + return td_api::make_object(progress_); + case Type::UploadingDocument: + return td_api::make_object(progress_); + case Type::ChoosingLocation: + return td_api::make_object(); + case Type::ChoosingContact: + return td_api::make_object(); + case Type::StartPlayingGame: + return td_api::make_object(); + case Type::RecordingVideoNote: + return td_api::make_object(); + case Type::UploadingVideoNote: + return td_api::make_object(progress_); + default: + UNREACHABLE(); + return td_api::make_object(); + } +} + +bool DialogAction::is_cancelled_by_message_of_type(MessageContentType message_content_type) const { + if (message_content_type == MessageContentType::None) { + return true; + } + + if (type_ == Type::Typing) { + return message_content_type == MessageContentType::Text || message_content_type == MessageContentType::Game || + can_have_message_content_caption(message_content_type); + } + + switch (message_content_type) { + case MessageContentType::Animation: + case MessageContentType::Audio: + case MessageContentType::Document: + return type_ == Type::UploadingDocument; + case MessageContentType::ExpiredPhoto: + case MessageContentType::Photo: + return type_ == Type::UploadingPhoto; + case MessageContentType::ExpiredVideo: + case MessageContentType::Video: + return type_ == Type::RecordingVideo || type_ == Type::UploadingVideo; + case MessageContentType::VideoNote: + return type_ == Type::RecordingVideoNote || type_ == Type::UploadingVideoNote; + case MessageContentType::VoiceNote: + return type_ == Type::RecordingVoiceNote || type_ == Type::UploadingVoiceNote; + case MessageContentType::Contact: + return type_ == Type::ChoosingContact; + case MessageContentType::LiveLocation: + case MessageContentType::Location: + case MessageContentType::Venue: + return type_ == Type::ChoosingLocation; + case MessageContentType::Game: + case MessageContentType::Invoice: + case MessageContentType::Sticker: + case MessageContentType::Text: + case MessageContentType::Unsupported: + case MessageContentType::ChatCreate: + case MessageContentType::ChatChangeTitle: + case MessageContentType::ChatChangePhoto: + case MessageContentType::ChatDeletePhoto: + case MessageContentType::ChatDeleteHistory: + case MessageContentType::ChatAddUsers: + case MessageContentType::ChatJoinedByLink: + case MessageContentType::ChatDeleteUser: + case MessageContentType::ChatMigrateTo: + case MessageContentType::ChannelCreate: + case MessageContentType::ChannelMigrateFrom: + case MessageContentType::PinMessage: + case MessageContentType::GameScore: + case MessageContentType::ScreenshotTaken: + case MessageContentType::ChatSetTtl: + case MessageContentType::Call: + case MessageContentType::PaymentSuccessful: + case MessageContentType::ContactRegistered: + case MessageContentType::CustomServiceAction: + case MessageContentType::WebsiteConnected: + case MessageContentType::PassportDataSent: + case MessageContentType::PassportDataReceived: + case MessageContentType::Poll: + case MessageContentType::Dice: + return false; + default: + UNREACHABLE(); + return false; + } +} + +DialogAction DialogAction::get_uploading_action(MessageContentType message_content_type, int32 progress) { + switch (message_content_type) { + case MessageContentType::Animation: + case MessageContentType::Audio: + case MessageContentType::Document: + return DialogAction(Type::UploadingDocument, progress); + case MessageContentType::Photo: + return DialogAction(Type::UploadingPhoto, progress); + case MessageContentType::Video: + return DialogAction(Type::UploadingVideo, progress); + case MessageContentType::VideoNote: + return DialogAction(Type::UploadingVideoNote, progress); + case MessageContentType::VoiceNote: + return DialogAction(Type::UploadingVoiceNote, progress); + default: + return DialogAction(); + } +} + +StringBuilder &operator<<(StringBuilder &string_builder, const DialogAction &action) { + string_builder << "ChatAction"; + const char *type = [action_type = action.type_] { + switch (action_type) { + case DialogAction::Type::Cancel: + return "Cancel"; + case DialogAction::Type::Typing: + return "Typing"; + case DialogAction::Type::RecordingVideo: + return "RecordingVideo"; + case DialogAction::Type::UploadingVideo: + return "UploadingVideo"; + case DialogAction::Type::RecordingVoiceNote: + return "RecordingVoiceNote"; + case DialogAction::Type::UploadingVoiceNote: + return "UploadingVoiceNote"; + case DialogAction::Type::UploadingPhoto: + return "UploadingPhoto"; + case DialogAction::Type::UploadingDocument: + return "UploadingDocument"; + case DialogAction::Type::ChoosingLocation: + return "ChoosingLocation"; + case DialogAction::Type::ChoosingContact: + return "ChoosingContact"; + case DialogAction::Type::StartPlayingGame: + return "StartPlayingGame"; + case DialogAction::Type::RecordingVideoNote: + return "RecordingVideoNote"; + case DialogAction::Type::UploadingVideoNote: + return "UploadingVideoNote"; + default: + UNREACHABLE(); + return "Cancel"; + } + }(); + string_builder << type << "Action"; + if (action.progress_ != 0) { + string_builder << '(' << action.progress_ << "%)"; + } + return string_builder; +} + +} // namespace td diff --git a/td/telegram/DialogAction.h b/td/telegram/DialogAction.h new file mode 100644 index 000000000..f8a553af4 --- /dev/null +++ b/td/telegram/DialogAction.h @@ -0,0 +1,73 @@ +// +// 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/MessageContentType.h" +#include "td/telegram/secret_api.h" +#include "td/telegram/td_api.h" +#include "td/telegram/telegram_api.h" + +#include "td/utils/common.h" +#include "td/utils/StringBuilder.h" +#include "td/utils/tl_helpers.h" + +namespace td { + +class DialogAction { + public: + enum class Type : int32 { + Cancel, + Typing, + RecordingVideo, + UploadingVideo, + RecordingVoiceNote, + UploadingVoiceNote, + UploadingPhoto, + UploadingDocument, + ChoosingLocation, + ChoosingContact, + StartPlayingGame, + RecordingVideoNote, + UploadingVideoNote + }; + Type type_ = Type::Cancel; + int32 progress_ = 0; + + DialogAction() = default; + + DialogAction(Type type, int32 progress); + + explicit DialogAction(tl_object_ptr &&action); + + explicit DialogAction(tl_object_ptr &&action); + + tl_object_ptr get_input_send_message_action() const; + + tl_object_ptr get_secret_input_send_message_action() const; + + td_api::object_ptr get_chat_action_object() const; + + bool is_cancelled_by_message_of_type(MessageContentType message_content_type) const; + + static DialogAction get_uploading_action(MessageContentType message_content_type, int32 progress); + + private: + void init(Type type); + void init(Type type, int32 progress); +}; + +inline bool operator==(const DialogAction &lhs, const DialogAction &rhs) { + return lhs.type_ == rhs.type_ && lhs.progress_ == rhs.progress_; +} + +inline bool operator!=(const DialogAction &lhs, const DialogAction &rhs) { + return !(lhs == rhs); +} + +StringBuilder &operator<<(StringBuilder &string_builder, const DialogAction &action); + +} // namespace td diff --git a/td/telegram/DialogAdministrator.cpp b/td/telegram/DialogAdministrator.cpp index 76dcccbf3..9bb4a8de0 100644 --- a/td/telegram/DialogAdministrator.cpp +++ b/td/telegram/DialogAdministrator.cpp @@ -19,7 +19,7 @@ td_api::object_ptr DialogAdministrator::get_chat_admi } StringBuilder &operator<<(StringBuilder &string_builder, const DialogAdministrator &administrator) { - return string_builder << "DialogAdministrator[" << administrator.user_id_ << ", title = " << administrator.rank_ + return string_builder << "ChatAdministrator[" << administrator.user_id_ << ", title = " << administrator.rank_ << ", is_owner = " << administrator.is_creator_ << "]"; } diff --git a/td/telegram/LanguagePackManager.cpp b/td/telegram/LanguagePackManager.cpp index d718ac9cb..f7b210eb8 100644 --- a/td/telegram/LanguagePackManager.cpp +++ b/td/telegram/LanguagePackManager.cpp @@ -242,7 +242,7 @@ string LanguagePackManager::get_main_language_code() { if (language_pack_.empty() || language_code_.empty()) { return "en"; } - if (language_code_.size() <= 2) { + if (language_code_.size() == 2) { return language_code_; } @@ -267,7 +267,8 @@ string LanguagePackManager::get_main_language_code() { } if (info == nullptr) { - LOG(ERROR) << "Failed to find information about chosen language " << language_code_; + LOG(WARNING) << "Failed to find information about chosen language " << language_code_ + << ", ensure that valid language pack ID is used"; if (!is_custom_language_code(language_code_)) { search_language_info(language_code_, Auto()); } @@ -308,11 +309,12 @@ vector LanguagePackManager::get_used_language_codes() { } vector result; - if (language_code_.size() <= 2) { + if (language_code_.size() == 2) { result.push_back(language_code_); } if (info == nullptr) { - LOG(ERROR) << "Failed to find information about chosen language " << language_code_; + LOG(WARNING) << "Failed to find information about chosen language " << language_code_ + << ", ensure that valid language pack ID is used"; if (!is_custom_language_code(language_code_)) { search_language_info(language_code_, Auto()); } diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 5450fad0e..469fb8317 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -399,21 +399,19 @@ class GetDiscussionMessageQuery : public Td::ResultHandler { Promise> promise_; DialogId dialog_id_; MessageId message_id_; - ChannelId expected_channel_id_; + DialogId expected_dialog_id_; MessageId expected_message_id_; public: explicit GetDiscussionMessageQuery(Promise> &&promise) : promise_(std::move(promise)) { } - void send(DialogId dialog_id, MessageId message_id, ChannelId expected_channel_id, MessageId expected_message_id) { + void send(DialogId dialog_id, MessageId message_id, DialogId expected_dialog_id, MessageId expected_message_id) { dialog_id_ = dialog_id; message_id_ = message_id; - expected_channel_id_ = expected_channel_id; + expected_dialog_id_ = expected_dialog_id; expected_message_id_ = expected_message_id; - if (!expected_channel_id_.is_valid()) { - return promise_.set_error(Status::Error(500, "Wrong message specified")); - } + CHECK(expected_dialog_id_.is_valid()); auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); CHECK(input_peer != nullptr); send_query(G()->net_query_creator().create( @@ -443,7 +441,7 @@ class GetDiscussionMessageQuery : public Td::ResultHandler { if ((ptr->flags_ & telegram_api::messages_discussionMessage::READ_OUTBOX_MAX_ID_MASK) != 0) { last_read_outbox_message_id = MessageId(ServerMessageId(ptr->read_outbox_max_id_)); } - if (DialogId(expected_channel_id_) != dialog_id_) { + if (expected_dialog_id_ != dialog_id_) { td->messages_manager_->on_update_read_message_comments(dialog_id_, message_id_, max_message_id, last_read_inbox_message_id, last_read_outbox_message_id); } @@ -455,7 +453,7 @@ class GetDiscussionMessageQuery : public Td::ResultHandler { "GetDiscussionMessageQuery"); if (full_message_id.get_message_id().is_valid()) { full_message_ids.push_back(full_message_id); - if (full_message_id.get_dialog_id() != DialogId(expected_channel_id_)) { + if (full_message_id.get_dialog_id() != expected_dialog_id_) { return on_error(id, Status::Error(500, "Expected messages in a different chat")); } if (full_message_id.get_message_id() == expected_message_id_) { @@ -467,16 +465,16 @@ class GetDiscussionMessageQuery : public Td::ResultHandler { top_message_id = full_message_ids.back().get_message_id(); } if (top_message_id.is_valid()) { - td->messages_manager_->on_update_read_message_comments(DialogId(expected_channel_id_), top_message_id, - max_message_id, last_read_inbox_message_id, - last_read_outbox_message_id); + td->messages_manager_->on_update_read_message_comments(expected_dialog_id_, top_message_id, max_message_id, + last_read_inbox_message_id, last_read_outbox_message_id); } promise_.set_value(std::move(full_message_ids)); } void on_error(uint64 id, Status status) override { - // because the error can be caused by the linked channel - // td->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetDiscussionMessageQuery"); + if (expected_dialog_id_ == dialog_id_) { + td->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetDiscussionMessageQuery"); + } promise_.set_error(std::move(status)); } }; @@ -6513,6 +6511,12 @@ bool MessagesManager::is_active_message_reply_info(DialogId dialog_id, const Mes if (dialog_id.get_type() != DialogType::Channel) { return false; } + + auto channel_id = dialog_id.get_channel_id(); + if (!td_->contacts_manager_->get_channel_has_linked_channel(channel_id)) { + return false; + } + if (!info.is_comment) { return true; } @@ -6520,10 +6524,6 @@ bool MessagesManager::is_active_message_reply_info(DialogId dialog_id, const Mes return true; } - auto channel_id = dialog_id.get_channel_id(); - if (!td_->contacts_manager_->get_channel_has_linked_channel(channel_id)) { - return false; - } auto linked_channel_id = td_->contacts_manager_->get_channel_linked_channel_id(channel_id); if (!linked_channel_id.is_valid()) { // keep the comment button while linked channel is unknown @@ -6559,27 +6559,23 @@ td_api::object_ptr MessagesManager::get_message_ return nullptr; } - int32 reply_count = -1; - vector recent_replier_user_ids; - MessageId last_read_inbox_message_id; - MessageId last_read_outbox_message_id; - MessageId max_message_id; + td_api::object_ptr reply_info; if (is_visible_reply_info) { - reply_count = m->reply_info.reply_count; + vector recent_replier_user_ids; for (auto recent_replier_dialog_id : m->reply_info.recent_replier_dialog_ids) { if (recent_replier_dialog_id.get_type() == DialogType::User) { recent_replier_user_ids.push_back(recent_replier_dialog_id.get_user_id()); } } - last_read_inbox_message_id = m->reply_info.last_read_inbox_message_id; - last_read_outbox_message_id = m->reply_info.last_read_outbox_message_id; - max_message_id = m->reply_info.max_message_id; + reply_info = td_api::make_object( + m->reply_info.reply_count, + td_->contacts_manager_->get_user_ids_object(recent_replier_user_ids, "get_message_interaction_info_object"), + m->reply_info.last_read_inbox_message_id.get(), m->reply_info.last_read_outbox_message_id.get(), + m->reply_info.max_message_id.get()); + CHECK(reply_info->reply_count_ >= 0); } - return td_api::make_object( - m->view_count, m->forward_count, reply_count, - td_->contacts_manager_->get_user_ids_object(recent_replier_user_ids, "get_message_interaction_info_object"), - last_read_inbox_message_id.get(), last_read_outbox_message_id.get(), max_message_id.get()); + return td_api::make_object(m->view_count, m->forward_count, std::move(reply_info)); } bool MessagesManager::update_message_interaction_info(DialogId dialog_id, Message *m, int32 view_count, @@ -6845,87 +6841,17 @@ void MessagesManager::on_update_delete_scheduled_messages(DialogId dialog_id, send_update_chat_has_scheduled_messages(d, true); } -bool MessagesManager::need_cancel_user_dialog_action(int32 action_id, MessageContentType message_content_type) { - if (message_content_type == MessageContentType::None) { - return true; - } - - if (action_id == td_api::chatActionTyping::ID) { - return message_content_type == MessageContentType::Text || message_content_type == MessageContentType::Game || - can_have_message_content_caption(message_content_type); - } - - switch (message_content_type) { - case MessageContentType::Animation: - case MessageContentType::Audio: - case MessageContentType::Document: - return action_id == td_api::chatActionUploadingDocument::ID; - case MessageContentType::ExpiredPhoto: - case MessageContentType::Photo: - return action_id == td_api::chatActionUploadingPhoto::ID; - case MessageContentType::ExpiredVideo: - case MessageContentType::Video: - return action_id == td_api::chatActionRecordingVideo::ID || action_id == td_api::chatActionUploadingVideo::ID; - case MessageContentType::VideoNote: - return action_id == td_api::chatActionRecordingVideoNote::ID || - action_id == td_api::chatActionUploadingVideoNote::ID; - case MessageContentType::VoiceNote: - return action_id == td_api::chatActionRecordingVoiceNote::ID || - action_id == td_api::chatActionUploadingVoiceNote::ID; - case MessageContentType::Contact: - return action_id == td_api::chatActionChoosingContact::ID; - case MessageContentType::LiveLocation: - case MessageContentType::Location: - case MessageContentType::Venue: - return action_id == td_api::chatActionChoosingLocation::ID; - case MessageContentType::Game: - case MessageContentType::Invoice: - case MessageContentType::Sticker: - case MessageContentType::Text: - case MessageContentType::Unsupported: - case MessageContentType::ChatCreate: - case MessageContentType::ChatChangeTitle: - case MessageContentType::ChatChangePhoto: - case MessageContentType::ChatDeletePhoto: - case MessageContentType::ChatDeleteHistory: - case MessageContentType::ChatAddUsers: - case MessageContentType::ChatJoinedByLink: - case MessageContentType::ChatDeleteUser: - case MessageContentType::ChatMigrateTo: - case MessageContentType::ChannelCreate: - case MessageContentType::ChannelMigrateFrom: - case MessageContentType::PinMessage: - case MessageContentType::GameScore: - case MessageContentType::ScreenshotTaken: - case MessageContentType::ChatSetTtl: - case MessageContentType::Call: - case MessageContentType::PaymentSuccessful: - case MessageContentType::ContactRegistered: - case MessageContentType::CustomServiceAction: - case MessageContentType::WebsiteConnected: - case MessageContentType::PassportDataSent: - case MessageContentType::PassportDataReceived: - case MessageContentType::Poll: - case MessageContentType::Dice: - return false; - default: - UNREACHABLE(); - return false; - } -} - void MessagesManager::on_user_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, UserId user_id, - tl_object_ptr &&action, int32 date, - MessageContentType message_content_type) { + DialogAction action, int32 date, MessageContentType message_content_type) { if (td_->auth_manager_->is_bot() || !user_id.is_valid() || is_broadcast_channel(dialog_id)) { return; } - if (action != nullptr || message_content_type != MessageContentType::None) { + bool is_canceled = action == DialogAction(); + if (!is_canceled || message_content_type != MessageContentType::None) { td_->contacts_manager_->on_update_user_local_was_online(user_id, date); } - bool is_canceled = action == nullptr || action->get_id() == td_api::chatActionCancel::ID; if (is_canceled) { auto actions_it = active_dialog_actions_.find(dialog_id); if (actions_it == active_dialog_actions_.end()) { @@ -6940,7 +6866,7 @@ void MessagesManager::on_user_dialog_action(DialogId dialog_id, MessageId top_th } if (!td_->contacts_manager_->is_user_bot(user_id) && - !need_cancel_user_dialog_action(it->action_id, message_content_type)) { + !it->action.is_cancelled_by_message_of_type(message_content_type)) { return; } @@ -6952,9 +6878,6 @@ void MessagesManager::on_user_dialog_action(DialogId dialog_id, MessageId top_th LOG(DEBUG) << "Cancel action timeout in " << dialog_id; active_dialog_action_timeout_.cancel_timeout(dialog_id.get()); } - if (action == nullptr) { - action = make_tl_object(); - } } else { if (date < G()->unix_time_cached() - DIALOG_ACTION_TIMEOUT - 60) { LOG(DEBUG) << "Ignore too old action of " << user_id << " in " << dialog_id << " sent at " << date; @@ -6964,43 +6887,22 @@ void MessagesManager::on_user_dialog_action(DialogId dialog_id, MessageId top_th auto it = std::find_if(active_actions.begin(), active_actions.end(), [user_id](const ActiveDialogAction &action) { return action.user_id == user_id; }); MessageId prev_top_thread_message_id; - int32 prev_action_id = 0; - int32 prev_progress = 0; + DialogAction prev_action; if (it != active_actions.end()) { LOG(DEBUG) << "Re-add action of " << user_id << " in " << dialog_id; prev_top_thread_message_id = it->top_thread_message_id; - prev_action_id = it->action_id; - prev_progress = it->progress; + prev_action = it->action; active_actions.erase(it); } else { LOG(DEBUG) << "Add action of " << user_id << " in " << dialog_id; } - auto action_id = action->get_id(); - auto progress = [&] { - switch (action_id) { - case td_api::chatActionUploadingVideo::ID: - return static_cast(*action).progress_; - case td_api::chatActionUploadingVoiceNote::ID: - return static_cast(*action).progress_; - case td_api::chatActionUploadingPhoto::ID: - return static_cast(*action).progress_; - case td_api::chatActionUploadingDocument::ID: - return static_cast(*action).progress_; - case td_api::chatActionUploadingVideoNote::ID: - return static_cast(*action).progress_; - default: - return 0; - } - }(); - active_actions.emplace_back(top_thread_message_id, user_id, action_id, Time::now()); - if (top_thread_message_id == prev_top_thread_message_id && action_id == prev_action_id && - progress <= prev_progress) { + active_actions.emplace_back(top_thread_message_id, user_id, action, Time::now()); + if (top_thread_message_id == prev_top_thread_message_id && action == prev_action) { return; } if (top_thread_message_id != prev_top_thread_message_id && prev_top_thread_message_id.is_valid()) { - send_update_user_chat_action(dialog_id, prev_top_thread_message_id, user_id, - td_api::make_object()); + send_update_user_chat_action(dialog_id, prev_top_thread_message_id, user_id, DialogAction()); } if (active_actions.size() == 1u) { LOG(DEBUG) << "Set action timeout in " << dialog_id; @@ -7010,9 +6912,9 @@ void MessagesManager::on_user_dialog_action(DialogId dialog_id, MessageId top_th if (!G()->shared_config().get_option_boolean("ignore_update_user_chat_action")) { if (top_thread_message_id.is_valid()) { - send_update_user_chat_action(dialog_id, MessageId(), user_id, copy_chat_action_object(action)); + send_update_user_chat_action(dialog_id, MessageId(), user_id, action); } - send_update_user_chat_action(dialog_id, top_thread_message_id, user_id, std::move(action)); + send_update_user_chat_action(dialog_id, top_thread_message_id, user_id, action); } } @@ -7023,7 +6925,7 @@ void MessagesManager::cancel_user_dialog_action(DialogId dialog_id, const Messag return; } - on_user_dialog_action(dialog_id, MessageId(), m->sender_user_id, nullptr, m->date, m->content->get_type()); + on_user_dialog_action(dialog_id, MessageId(), m->sender_user_id, DialogAction(), m->date, m->content->get_type()); } void MessagesManager::add_pending_channel_update(DialogId dialog_id, tl_object_ptr &&update, @@ -7768,7 +7670,7 @@ void MessagesManager::repair_dialog_action_bar(Dialog *d, const char *source) { d->know_action_bar = false; if (have_input_peer(dialog_id, AccessRights::Read)) { create_actor( - "RepairDialogActionBarActor", 1.0, + "RepairChatActionBarActor", 1.0, PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, source](Result result) { send_closure(actor_id, &MessagesManager::reget_dialog_action_bar, dialog_id, source); })) @@ -16064,6 +15966,24 @@ FullMessageId MessagesManager::get_replied_message(DialogId dialog_id, MessageId return replied_message_id; } +Result MessagesManager::get_top_thread_full_message_id(DialogId dialog_id, const Message *m) const { + CHECK(m != nullptr); + if (m->message_id.is_scheduled()) { + return Status::Error(400, "Message is scheduled"); + } + if (m->reply_info.is_comment) { + if (!is_visible_message_reply_info(dialog_id, m)) { + return Status::Error(400, "Message has no comments"); + } + return FullMessageId{DialogId(m->reply_info.channel_id), m->linked_top_thread_message_id}; + } else { + if (!m->top_thread_message_id.is_valid() || !is_visible_message_reply_info(dialog_id, m)) { + return Status::Error(400, "Message has no thread"); + } + return FullMessageId{dialog_id, m->top_thread_message_id}; + } +} + void MessagesManager::get_message_thread(DialogId dialog_id, MessageId message_id, Promise &&promise) { LOG(INFO) << "Get message thread from " << message_id << " in " << dialog_id; @@ -16086,21 +16006,7 @@ void MessagesManager::get_message_thread(DialogId dialog_id, MessageId message_i return promise.set_error(Status::Error(400, "Message not found")); } - ChannelId message_thread_channel_id; - MessageId top_thread_message_id; - if (m->reply_info.is_comment) { - if (!is_visible_message_reply_info(dialog_id, m)) { - return promise.set_error(Status::Error(400, "Message has no comments")); - } - message_thread_channel_id = m->reply_info.channel_id; - } else { - if (!m->top_thread_message_id.is_valid()) { - return promise.set_error(Status::Error(400, "Message has no thread")); - } - message_thread_channel_id = dialog_id.get_channel_id(); - top_thread_message_id = m->top_thread_message_id; - } - CHECK(message_thread_channel_id.is_valid()); + TRY_RESULT_PROMISE(promise, top_thread_full_message_id, get_top_thread_full_message_id(dialog_id, m)); auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, message_id, @@ -16113,7 +16019,8 @@ void MessagesManager::get_message_thread(DialogId dialog_id, MessageId message_i }); td_->create_handler(std::move(query_promise)) - ->send(dialog_id, message_id, message_thread_channel_id, top_thread_message_id); + ->send(dialog_id, message_id, top_thread_full_message_id.get_dialog_id(), + top_thread_full_message_id.get_message_id()); } void MessagesManager::on_get_discussion_message(DialogId dialog_id, MessageId message_id, @@ -16193,11 +16100,13 @@ td_api::object_ptr MessagesManager::get_message_threa MessageId top_thread_message_id; td_api::object_ptr draft_message; - if (!info.message_ids.empty() && can_send_message(d->dialog_id).is_ok()) { + if (!info.message_ids.empty()) { top_thread_message_id = info.message_ids.back(); - const Message *m = get_message_force(d, top_thread_message_id, "get_message_thread_info_object 2"); - if (m != nullptr && !m->reply_info.is_comment && is_active_message_reply_info(d->dialog_id, m->reply_info)) { - draft_message = get_draft_message_object(m->thread_draft_message); + if (can_send_message(d->dialog_id).is_ok()) { + const Message *m = get_message_force(d, top_thread_message_id, "get_message_thread_info_object 2"); + if (m != nullptr && !m->reply_info.is_comment && is_active_message_reply_info(d->dialog_id, m->reply_info)) { + draft_message = get_draft_message_object(m->thread_draft_message); + } } } return td_api::make_object(d->dialog_id.get(), top_thread_message_id.get(), @@ -16789,7 +16698,7 @@ void MessagesManager::on_get_message_link_message(MessageLinkInfo &&info, Dialog }); td_->create_handler(std::move(query_promise)) - ->send(dialog_id, info.message_id, m->reply_info.channel_id, MessageId()); + ->send(dialog_id, info.message_id, DialogId(m->reply_info.channel_id), MessageId()); } void MessagesManager::on_get_message_link_discussion_message(MessageLinkInfo &&info, DialogId comment_dialog_id, @@ -19826,8 +19735,7 @@ std::pair> MessagesManager::get_message_thread_histo return {}; } - DialogId message_thread_dialog_id; - MessageId top_thread_message_id; + FullMessageId top_thread_full_message_id; { Message *m = get_message_force(d, message_id, "get_message_thread_history 1"); if (m == nullptr) { @@ -19835,35 +19743,27 @@ std::pair> MessagesManager::get_message_thread_histo return {}; } - if (m->reply_info.is_comment) { - if (!is_visible_message_reply_info(dialog_id, m)) { - promise.set_error(Status::Error(400, "Message has no comments")); - return {}; - } - if (!m->linked_top_thread_message_id.is_valid()) { - get_message_thread( - dialog_id, message_id, - PromiseCreator::lambda([promise = std::move(promise)](Result &&result) mutable { - if (result.is_error()) { - promise.set_error(result.move_as_error()); - } else { - promise.set_value(Unit()); - } - })); - return {}; - } - message_thread_dialog_id = DialogId(m->reply_info.channel_id); - top_thread_message_id = m->linked_top_thread_message_id; - } else { - if (!m->top_thread_message_id.is_valid()) { - promise.set_error(Status::Error(400, "Message has no thread")); - return {}; - } - message_thread_dialog_id = dialog_id; - top_thread_message_id = m->top_thread_message_id; + auto r_top_thread_full_message_id = get_top_thread_full_message_id(dialog_id, m); + if (r_top_thread_full_message_id.is_error()) { + promise.set_error(r_top_thread_full_message_id.move_as_error()); + return {}; + } + top_thread_full_message_id = r_top_thread_full_message_id.move_as_ok(); + + if (!top_thread_full_message_id.get_message_id().is_valid()) { + CHECK(m->reply_info.is_comment); + get_message_thread( + dialog_id, message_id, + PromiseCreator::lambda([promise = std::move(promise)](Result &&result) mutable { + if (result.is_error()) { + promise.set_error(result.move_as_error()); + } else { + promise.set_value(Unit()); + } + })); + return {}; } } - CHECK(top_thread_message_id.is_valid()); if (random_id != 0) { // request has already been sent before @@ -19880,12 +19780,12 @@ std::pair> MessagesManager::get_message_thread_histo d = get_dialog(dialog_id); CHECK(d != nullptr); } - if (dialog_id != message_thread_dialog_id) { + if (dialog_id != top_thread_full_message_id.get_dialog_id()) { promise.set_error(Status::Error(500, "Receive messages in an unexpected chat")); return {}; } - auto yet_unsent_it = d->yet_unsent_thread_message_ids.find(top_thread_message_id); + auto yet_unsent_it = d->yet_unsent_thread_message_ids.find(top_thread_full_message_id.get_message_id()); if (yet_unsent_it != d->yet_unsent_thread_message_ids.end()) { const std::set &message_ids = yet_unsent_it->second; auto merge_message_ids = get_message_history_slice(message_ids.begin(), message_ids.lower_bound(from_message_id), @@ -19896,7 +19796,7 @@ std::pair> MessagesManager::get_message_thread_histo result = std::move(new_result); } - Message *top_m = get_message_force(d, top_thread_message_id, "get_message_thread_history 2"); + Message *top_m = get_message_force(d, top_thread_full_message_id.get_message_id(), "get_message_thread_history 2"); if (top_m != nullptr && !top_m->local_thread_message_ids.empty()) { vector &message_ids = top_m->local_thread_message_ids; vector merge_message_ids; @@ -21798,9 +21698,7 @@ tl_object_ptr MessagesManager::get_message_object(DialogId dial bool can_be_edited = for_event_log ? false : can_edit_message(dialog_id, m, false, td_->auth_manager_->is_bot()); bool can_be_forwarded = for_event_log ? false : can_forward_message(dialog_id, m); bool can_get_statistics = for_event_log ? false : can_get_message_statistics(dialog_id, m); - bool can_get_message_thread = for_event_log || is_scheduled ? false - : is_visible_message_reply_info(dialog_id, m) || - m->top_thread_message_id.is_valid(); + bool can_get_message_thread = for_event_log ? false : get_top_thread_full_message_id(dialog_id, m).is_ok(); auto via_bot_user_id = td_->contacts_manager_->get_user_id_object(m->via_bot_user_id, "via_bot_user_id"); auto media_album_id = for_event_log ? static_cast(0) : m->media_album_id; auto reply_to_message_id = for_event_log ? static_cast(0) : m->reply_to_message_id.get(); @@ -27314,18 +27212,18 @@ void MessagesManager::send_update_chat_has_scheduled_messages(Dialog *d, bool fr } void MessagesManager::send_update_user_chat_action(DialogId dialog_id, MessageId top_thread_message_id, UserId user_id, - td_api::object_ptr action) { + DialogAction action) { if (td_->auth_manager_->is_bot()) { return; } - LOG(DEBUG) << "Send action of " << user_id << " in thread of " << top_thread_message_id << " in " << dialog_id << ": " - << to_string(action); - send_closure( - G()->td(), &Td::send_update, - make_tl_object( - dialog_id.get(), top_thread_message_id.get(), - td_->contacts_manager_->get_user_id_object(user_id, "send_update_user_chat_action"), std::move(action))); + LOG(DEBUG) << "Send " << action << " of " << user_id << " in thread of " << top_thread_message_id << " in " + << dialog_id; + send_closure(G()->td(), &Td::send_update, + make_tl_object( + dialog_id.get(), top_thread_message_id.get(), + td_->contacts_manager_->get_user_id_object(user_id, "send_update_user_chat_action"), + action.get_chat_action_object())); } void MessagesManager::on_send_message_get_quick_ack(int64 random_id) { @@ -28959,58 +28857,8 @@ bool MessagesManager::is_dialog_action_unneeded(DialogId dialog_id) const { return false; } -tl_object_ptr MessagesManager::copy_chat_action_object( - const tl_object_ptr &action) { - CHECK(action != nullptr); - switch (action->get_id()) { - case td_api::chatActionCancel::ID: - return make_tl_object(); - case td_api::chatActionTyping::ID: - return make_tl_object(); - case td_api::chatActionRecordingVideo::ID: - return make_tl_object(); - case td_api::chatActionUploadingVideo::ID: { - auto progress = static_cast(*action).progress_; - return make_tl_object(progress); - } - case td_api::chatActionRecordingVoiceNote::ID: - return make_tl_object(); - case td_api::chatActionUploadingVoiceNote::ID: { - auto progress = static_cast(*action).progress_; - return make_tl_object(progress); - } - case td_api::chatActionUploadingPhoto::ID: { - auto progress = static_cast(*action).progress_; - return make_tl_object(progress); - } - case td_api::chatActionUploadingDocument::ID: { - auto progress = static_cast(*action).progress_; - return make_tl_object(progress); - } - case td_api::chatActionChoosingLocation::ID: - return make_tl_object(); - case td_api::chatActionChoosingContact::ID: - return make_tl_object(); - case td_api::chatActionStartPlayingGame::ID: - return make_tl_object(); - case td_api::chatActionRecordingVideoNote::ID: - return make_tl_object(); - case td_api::chatActionUploadingVideoNote::ID: { - auto progress = static_cast(*action).progress_; - return make_tl_object(progress); - } - default: - UNREACHABLE(); - return nullptr; - } -} - -void MessagesManager::send_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, - const tl_object_ptr &action, Promise &&promise) { - if (action == nullptr) { - return promise.set_error(Status::Error(5, "Action must be non-empty")); - } - +void MessagesManager::send_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, DialogAction action, + Promise &&promise) { if (!have_dialog_force(dialog_id)) { return promise.set_error(Status::Error(5, "Chat not found")); } @@ -29032,117 +28880,19 @@ void MessagesManager::send_dialog_action(DialogId dialog_id, MessageId top_threa } if (dialog_id.get_type() == DialogType::SecretChat) { - tl_object_ptr send_action; - switch (action->get_id()) { - case td_api::chatActionCancel::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionTyping::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionRecordingVideo::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionUploadingVideo::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionRecordingVoiceNote::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionUploadingVoiceNote::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionUploadingPhoto::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionUploadingDocument::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionChoosingLocation::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionChoosingContact::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionRecordingVideoNote::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionUploadingVideoNote::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionStartPlayingGame::ID: - return promise.set_error(Status::Error(5, "Games are unsupported in secret chats")); - default: - UNREACHABLE(); - } send_closure(G()->secret_chats_manager(), &SecretChatsManager::send_message_action, dialog_id.get_secret_chat_id(), - std::move(send_action)); + action.get_secret_input_send_message_action()); promise.set_value(Unit()); return; } - tl_object_ptr send_action; - switch (action->get_id()) { - case td_api::chatActionCancel::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionTyping::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionRecordingVideo::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionUploadingVideo::ID: { - auto progress = static_cast(*action).progress_; - send_action = make_tl_object(progress); - break; - } - case td_api::chatActionRecordingVoiceNote::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionUploadingVoiceNote::ID: { - auto progress = static_cast(*action).progress_; - send_action = make_tl_object(progress); - break; - } - case td_api::chatActionUploadingPhoto::ID: { - auto progress = static_cast(*action).progress_; - send_action = make_tl_object(progress); - break; - } - case td_api::chatActionUploadingDocument::ID: { - auto progress = static_cast(*action).progress_; - send_action = make_tl_object(progress); - break; - } - case td_api::chatActionChoosingLocation::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionChoosingContact::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionStartPlayingGame::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionRecordingVideoNote::ID: - send_action = make_tl_object(); - break; - case td_api::chatActionUploadingVideoNote::ID: { - auto progress = static_cast(*action).progress_; - send_action = make_tl_object(progress); - break; - } - default: - UNREACHABLE(); - } - auto &query_ref = set_typing_query_[dialog_id]; if (!query_ref.empty() && !td_->auth_manager_->is_bot()) { LOG(INFO) << "Cancel previous set typing query"; cancel_query(query_ref); } query_ref = td_->create_handler(std::move(promise)) - ->send(dialog_id, top_thread_message_id, std::move(send_action)); + ->send(dialog_id, top_thread_message_id, action.get_input_send_message_action()); } void MessagesManager::on_send_dialog_action_timeout(DialogId dialog_id) { @@ -29194,31 +28944,12 @@ void MessagesManager::on_send_dialog_action_timeout(DialogId dialog_id) { progress = static_cast(100 * uploaded_size / total_size); } - td_api::object_ptr action; - switch (m->content->get_type()) { - case MessageContentType::Animation: - case MessageContentType::Audio: - case MessageContentType::Document: - action = td_api::make_object(progress); - break; - case MessageContentType::Photo: - action = td_api::make_object(progress); - break; - case MessageContentType::Video: - action = td_api::make_object(progress); - break; - case MessageContentType::VideoNote: - action = td_api::make_object(progress); - break; - case MessageContentType::VoiceNote: - action = td_api::make_object(progress); - break; - default: - return; + DialogAction action = DialogAction::get_uploading_action(m->content->get_type(), progress); + if (action == DialogAction()) { + return; } - CHECK(action != nullptr); - LOG(INFO) << "Send action in " << dialog_id << ": " << to_string(action); - send_dialog_action(dialog_id, m->top_thread_message_id, std::move(action), Auto()); + LOG(INFO) << "Send " << action << " in " << dialog_id; + send_dialog_action(dialog_id, m->top_thread_message_id, std::move(action), Promise()); } void MessagesManager::on_active_dialog_action_timeout(DialogId dialog_id) { @@ -29232,7 +28963,7 @@ void MessagesManager::on_active_dialog_action_timeout(DialogId dialog_id) { auto now = Time::now(); while (actions_it->second[0].start_time + DIALOG_ACTION_TIMEOUT < now + 0.1) { on_user_dialog_action(dialog_id, actions_it->second[0].top_thread_message_id, actions_it->second[0].user_id, - nullptr, 0); + DialogAction(), 0); actions_it = active_dialog_actions_.find(dialog_id); if (actions_it == active_dialog_actions_.end()) { @@ -29252,7 +28983,7 @@ void MessagesManager::clear_active_dialog_actions(DialogId dialog_id) { while (actions_it != active_dialog_actions_.end()) { CHECK(!actions_it->second.empty()); on_user_dialog_action(dialog_id, actions_it->second[0].top_thread_message_id, actions_it->second[0].user_id, - nullptr, 0); + DialogAction(), 0); actions_it = active_dialog_actions_.find(dialog_id); } } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 306a570e1..be1252544 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -9,6 +9,7 @@ #include "td/telegram/AccessRights.h" #include "td/telegram/ChannelId.h" #include "td/telegram/Dependencies.h" +#include "td/telegram/DialogAction.h" #include "td/telegram/DialogAdministrator.h" #include "td/telegram/DialogDate.h" #include "td/telegram/DialogDb.h" @@ -367,9 +368,8 @@ class MessagesManager : public Actor { void on_update_delete_scheduled_messages(DialogId dialog_id, vector &&server_message_ids); - void on_user_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, UserId user_id, - tl_object_ptr &&action, int32 date, - MessageContentType message_content_type = MessageContentType::None); + void on_user_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, UserId user_id, DialogAction action, + int32 date, MessageContentType message_content_type = MessageContentType::None); void read_history_inbox(DialogId dialog_id, MessageId max_message_id, int32 unread_count, const char *source); @@ -478,8 +478,8 @@ class MessagesManager : public Actor { tl_object_ptr get_game_high_scores_object(int64 random_id); - void send_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, - const tl_object_ptr &action, Promise &&promise); + void send_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, DialogAction action, + Promise &&promise); vector get_dialog_lists_to_add_dialog(DialogId dialog_id); @@ -1937,6 +1937,8 @@ class MessagesManager : public Actor { bool is_visible_message_reply_info(DialogId dialog_id, const Message *m) const; + Result get_top_thread_full_message_id(DialogId dialog_id, const Message *m) const; + td_api::object_ptr get_message_interaction_info_object(DialogId dialog_id, const Message *m) const; @@ -2216,7 +2218,7 @@ class MessagesManager : public Actor { void send_update_chat_has_scheduled_messages(Dialog *d, bool from_deletion); void send_update_user_chat_action(DialogId dialog_id, MessageId top_thread_message_id, UserId user_id, - td_api::object_ptr action); + DialogAction action); void repair_dialog_action_bar(Dialog *d, const char *source); @@ -2353,8 +2355,6 @@ class MessagesManager : public Actor { bool update_dialog_silent_send_message(Dialog *d, bool silent_send_message); - static tl_object_ptr copy_chat_action_object(const tl_object_ptr &action); - bool is_dialog_action_unneeded(DialogId dialog_id) const; void on_send_dialog_action_timeout(DialogId dialog_id); @@ -2363,8 +2363,6 @@ class MessagesManager : public Actor { void clear_active_dialog_actions(DialogId dialog_id); - static bool need_cancel_user_dialog_action(int32 action_id, MessageContentType message_content_type); - void cancel_user_dialog_action(DialogId dialog_id, const Message *m); Dialog *get_dialog_by_message_id(MessageId message_id); @@ -3102,12 +3100,11 @@ class MessagesManager : public Actor { struct ActiveDialogAction { MessageId top_thread_message_id; UserId user_id; - int32 action_id; - int32 progress; + DialogAction action; double start_time; - ActiveDialogAction(MessageId top_thread_message_id, UserId user_id, int32 action_id, double start_time) - : top_thread_message_id(top_thread_message_id), user_id(user_id), action_id(action_id), start_time(start_time) { + ActiveDialogAction(MessageId top_thread_message_id, UserId user_id, DialogAction action, double start_time) + : top_thread_message_id(top_thread_message_id), user_id(user_id), action(action), start_time(start_time) { } }; diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index b16405c54..b159af3f0 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -5904,12 +5904,14 @@ vector StickersManager::get_emoji_language_codes(const vector &i Promise &promise) { vector language_codes = td_->language_pack_manager_->get_actor_unsafe()->get_used_language_codes(); auto system_language_code = G()->mtproto_header().get_system_language_code(); - if (!system_language_code.empty() && system_language_code.find('$') == string::npos) { - language_codes.push_back(system_language_code); + if (system_language_code.size() >= 2 && system_language_code.find('$') == string::npos && + (system_language_code.size() == 2 || system_language_code[2] == '-')) { + language_codes.push_back(system_language_code.substr(0, 2)); } for (auto &input_language_code : input_language_codes) { - if (!input_language_code.empty() && input_language_code.find('$') == string::npos) { - language_codes.push_back(input_language_code); + if (input_language_code.size() >= 2 && input_language_code.find('$') == string::npos && + (input_language_code.size() == 2 || input_language_code[2] == '-')) { + language_codes.push_back(input_language_code.substr(0, 2)); } } if (!text.empty()) { @@ -5929,7 +5931,7 @@ vector StickersManager::get_emoji_language_codes(const vector &i } if (language_codes.empty()) { - LOG(ERROR) << "List of language codes is empty"; + LOG(INFO) << "List of language codes is empty"; language_codes.push_back("en"); } std::sort(language_codes.begin(), language_codes.end()); @@ -5944,6 +5946,7 @@ vector StickersManager::get_emoji_language_codes(const vector &i if (it->second.empty()) { load_language_codes(std::move(language_codes), std::move(key), std::move(promise)); } else { + LOG(DEBUG) << "Have emoji language codes " << it->second; double now = Time::now_cached(); for (auto &language_code : it->second) { double last_difference_time = get_emoji_language_code_last_difference_time(language_code); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index aff45b6f5..b694bc4b0 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -24,6 +24,7 @@ #include "td/telegram/ContactsManager.h" #include "td/telegram/CountryInfoManager.h" #include "td/telegram/DeviceTokenManager.h" +#include "td/telegram/DialogAction.h" #include "td/telegram/DialogAdministrator.h" #include "td/telegram/DialogFilter.h" #include "td/telegram/DialogFilterId.h" @@ -5843,7 +5844,7 @@ void Td::on_request(uint64 id, const td_api::deleteChatReplyMarkup &request) { void Td::on_request(uint64 id, td_api::sendChatAction &request) { CREATE_OK_REQUEST_PROMISE(); messages_manager_->send_dialog_action(DialogId(request.chat_id_), MessageId(request.message_thread_id_), - std::move(request.action_), std::move(promise)); + DialogAction(std::move(request.action_)), std::move(promise)); } void Td::on_request(uint64 id, td_api::sendChatScreenshotTakenNotification &request) { diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index badccf3d7..5946e6adf 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -16,6 +16,7 @@ #include "td/telegram/ChatId.h" #include "td/telegram/ConfigManager.h" #include "td/telegram/ContactsManager.h" +#include "td/telegram/DialogAction.h" #include "td/telegram/DialogId.h" #include "td/telegram/FolderId.h" #include "td/telegram/Global.h" @@ -1829,55 +1830,6 @@ int32 UpdatesManager::get_short_update_date() const { return now; } -tl_object_ptr UpdatesManager::convert_send_message_action( - tl_object_ptr action) { - auto fix_progress = [](int32 progress) { - return progress <= 0 || progress > 100 ? 0 : progress; - }; - - switch (action->get_id()) { - case telegram_api::sendMessageCancelAction::ID: - return make_tl_object(); - case telegram_api::sendMessageTypingAction::ID: - return make_tl_object(); - case telegram_api::sendMessageRecordVideoAction::ID: - return make_tl_object(); - case telegram_api::sendMessageUploadVideoAction::ID: { - auto upload_video_action = move_tl_object_as(action); - return make_tl_object(fix_progress(upload_video_action->progress_)); - } - case telegram_api::sendMessageRecordAudioAction::ID: - return make_tl_object(); - case telegram_api::sendMessageUploadAudioAction::ID: { - auto upload_audio_action = move_tl_object_as(action); - return make_tl_object(fix_progress(upload_audio_action->progress_)); - } - case telegram_api::sendMessageUploadPhotoAction::ID: { - auto upload_photo_action = move_tl_object_as(action); - return make_tl_object(fix_progress(upload_photo_action->progress_)); - } - case telegram_api::sendMessageUploadDocumentAction::ID: { - auto upload_document_action = move_tl_object_as(action); - return make_tl_object(fix_progress(upload_document_action->progress_)); - } - case telegram_api::sendMessageGeoLocationAction::ID: - return make_tl_object(); - case telegram_api::sendMessageChooseContactAction::ID: - return make_tl_object(); - case telegram_api::sendMessageGamePlayAction::ID: - return make_tl_object(); - case telegram_api::sendMessageRecordRoundAction::ID: - return make_tl_object(); - case telegram_api::sendMessageUploadRoundAction::ID: { - auto upload_round_action = move_tl_object_as(action); - return make_tl_object(fix_progress(upload_round_action->progress_)); - } - default: - UNREACHABLE(); - return make_tl_object(); - } -} - void UpdatesManager::on_update(tl_object_ptr update, bool /*force_apply*/) { UserId user_id(update->user_id_); if (!td_->contacts_manager_->have_min_user(user_id)) { @@ -1890,8 +1842,7 @@ void UpdatesManager::on_update(tl_object_ptr upd return; } td_->messages_manager_->on_user_dialog_action(dialog_id, MessageId(), user_id, - convert_send_message_action(std::move(update->action_)), - get_short_update_date()); + DialogAction(std::move(update->action_)), get_short_update_date()); } void UpdatesManager::on_update(tl_object_ptr update, bool /*force_apply*/) { @@ -1906,8 +1857,7 @@ void UpdatesManager::on_update(tl_object_ptr return; } td_->messages_manager_->on_user_dialog_action(dialog_id, MessageId(), user_id, - convert_send_message_action(std::move(update->action_)), - get_short_update_date()); + DialogAction(std::move(update->action_)), get_short_update_date()); } void UpdatesManager::on_update(tl_object_ptr update, bool /*force_apply*/) { @@ -1930,8 +1880,7 @@ void UpdatesManager::on_update(tl_object_ptrmessages_manager_->on_user_dialog_action(dialog_id, top_thread_message_id, user_id, - convert_send_message_action(std::move(update->action_)), - get_short_update_date()); + DialogAction(std::move(update->action_)), get_short_update_date()); } void UpdatesManager::on_update(tl_object_ptr update, bool /*force_apply*/) { @@ -1950,7 +1899,7 @@ void UpdatesManager::on_update(tl_object_ptrmessages_manager_->on_user_dialog_action(dialog_id, MessageId(), user_id, - make_tl_object(), get_short_update_date()); + DialogAction(DialogAction::Type::Typing, 0), get_short_update_date()); } void UpdatesManager::on_update(tl_object_ptr update, bool /*force_apply*/) { diff --git a/td/telegram/UpdatesManager.h b/td/telegram/UpdatesManager.h index d60b73ba1..c81ce6c8b 100644 --- a/td/telegram/UpdatesManager.h +++ b/td/telegram/UpdatesManager.h @@ -136,9 +136,6 @@ class UpdatesManager : public Actor { int32 get_short_update_date() const; - static tl_object_ptr convert_send_message_action( - tl_object_ptr action); - void process_get_difference_updates(vector> &&new_messages, vector> &&new_encrypted_messages, vector> &&other_updates);