Merge remote-tracking branch 'td/master'

This commit is contained in:
Andrea Cavalli 2022-05-16 00:00:04 +02:00
commit a156fcfb1d
41 changed files with 817 additions and 362 deletions

View File

@ -416,6 +416,7 @@ set(TDLIB_SOURCE
td/telegram/SecretChatActor.cpp td/telegram/SecretChatActor.cpp
td/telegram/SecretChatDb.cpp td/telegram/SecretChatDb.cpp
td/telegram/SecretChatsManager.cpp td/telegram/SecretChatsManager.cpp
td/telegram/SecretInputMedia.cpp
td/telegram/SecureManager.cpp td/telegram/SecureManager.cpp
td/telegram/SecureStorage.cpp td/telegram/SecureStorage.cpp
td/telegram/SecureValue.cpp td/telegram/SecureValue.cpp

View File

@ -393,8 +393,7 @@ SecretInputMedia AnimationsManager::get_secret_input_media(FileId animation_file
auto *animation = get_animation(animation_file_id); auto *animation = get_animation(animation_file_id);
CHECK(animation != nullptr); CHECK(animation != nullptr);
auto file_view = td_->file_manager_->get_file_view(animation_file_id); auto file_view = td_->file_manager_->get_file_view(animation_file_id);
auto &encryption_key = file_view.encryption_key(); if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty()) {
if (!file_view.is_encrypted_secret() || encryption_key.empty()) {
return SecretInputMedia{}; return SecretInputMedia{};
} }
if (file_view.has_remote_location()) { if (file_view.has_remote_location()) {
@ -420,12 +419,13 @@ SecretInputMedia AnimationsManager::get_secret_input_media(FileId animation_file
} }
attributes.push_back(make_tl_object<secret_api::documentAttributeAnimated>()); attributes.push_back(make_tl_object<secret_api::documentAttributeAnimated>());
return SecretInputMedia{ return {std::move(input_file),
std::move(input_file), std::move(thumbnail),
make_tl_object<secret_api::decryptedMessageMediaDocument>( animation->thumbnail.dimensions,
std::move(thumbnail), animation->thumbnail.dimensions.width, animation->thumbnail.dimensions.height, animation->mime_type,
animation->mime_type, narrow_cast<int32>(file_view.size()), BufferSlice(encryption_key.key_slice()), file_view,
BufferSlice(encryption_key.iv_slice()), std::move(attributes), caption)}; std::move(attributes),
caption};
} }
void AnimationsManager::on_update_animation_search_emojis(string animation_search_emojis) { void AnimationsManager::on_update_animation_search_emojis(string animation_search_emojis) {
@ -885,12 +885,6 @@ string AnimationsManager::get_animation_search_text(FileId file_id) const {
return animation->file_name; return animation->file_name;
} }
void AnimationsManager::after_get_difference() {
if (td_->is_online() && !td_->auth_manager_->is_bot()) {
get_saved_animations(Auto());
}
}
void AnimationsManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const { void AnimationsManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const {
if (td_->auth_manager_->is_bot()) { if (td_->auth_manager_->is_bot()) {
return; return;

View File

@ -91,8 +91,6 @@ class AnimationsManager final : public Actor {
string get_animation_search_text(FileId file_id) const; string get_animation_search_text(FileId file_id) const;
void after_get_difference();
void get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const; void get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const;
private: private:

View File

@ -210,8 +210,7 @@ SecretInputMedia AudiosManager::get_secret_input_media(FileId audio_file_id,
auto *audio = get_audio(audio_file_id); auto *audio = get_audio(audio_file_id);
CHECK(audio != nullptr); CHECK(audio != nullptr);
auto file_view = td_->file_manager_->get_file_view(audio_file_id); auto file_view = td_->file_manager_->get_file_view(audio_file_id);
auto &encryption_key = file_view.encryption_key(); if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty()) {
if (!file_view.is_encrypted_secret() || encryption_key.empty()) {
return SecretInputMedia{}; return SecretInputMedia{};
} }
if (file_view.has_remote_location()) { if (file_view.has_remote_location()) {
@ -231,12 +230,13 @@ SecretInputMedia AudiosManager::get_secret_input_media(FileId audio_file_id,
secret_api::documentAttributeAudio::TITLE_MASK | secret_api::documentAttributeAudio::PERFORMER_MASK, secret_api::documentAttributeAudio::TITLE_MASK | secret_api::documentAttributeAudio::PERFORMER_MASK,
false /*ignored*/, audio->duration, audio->title, audio->performer, BufferSlice())); false /*ignored*/, audio->duration, audio->title, audio->performer, BufferSlice()));
return SecretInputMedia{ return {std::move(input_file),
std::move(input_file), std::move(thumbnail),
make_tl_object<secret_api::decryptedMessageMediaDocument>( audio->thumbnail.dimensions,
std::move(thumbnail), audio->thumbnail.dimensions.width, audio->thumbnail.dimensions.height, audio->mime_type, audio->mime_type,
narrow_cast<int32>(file_view.size()), BufferSlice(encryption_key.key_slice()), file_view,
BufferSlice(encryption_key.iv_slice()), std::move(attributes), caption)}; std::move(attributes),
caption};
} }
tl_object_ptr<telegram_api::InputMedia> AudiosManager::get_input_media( tl_object_ptr<telegram_api::InputMedia> AudiosManager::get_input_media(

View File

@ -39,13 +39,13 @@ void ConfigShared::set_option_empty(Slice name) {
} }
void ConfigShared::set_option_integer(Slice name, int64 value) { void ConfigShared::set_option_integer(Slice name, int64 value) {
if (set_option(name, PSLICE() << "I" << value)) { if (set_option(name, PSLICE() << 'I' << value)) {
on_option_updated(name); on_option_updated(name);
} }
} }
void ConfigShared::set_option_string(Slice name, Slice value) { void ConfigShared::set_option_string(Slice name, Slice value) {
if (set_option(name, PSLICE() << "S" << value)) { if (set_option(name, PSLICE() << 'S' << value)) {
on_option_updated(name); on_option_updated(name);
} }
} }
@ -73,32 +73,32 @@ bool ConfigShared::get_option_boolean(Slice name, bool default_value) const {
if (value == "Bfalse") { if (value == "Bfalse") {
return false; return false;
} }
LOG(ERROR) << "Found \"" << value << "\" instead of boolean option"; LOG(ERROR) << "Found \"" << value << "\" instead of boolean option " << name;
return default_value; return default_value;
} }
int64 ConfigShared::get_option_integer(Slice name, int64 default_value) const { int64 ConfigShared::get_option_integer(Slice name, int64 default_value) const {
auto str_value = get_option(name); auto value = get_option(name);
if (str_value.empty()) { if (value.empty()) {
return default_value; return default_value;
} }
if (str_value[0] != 'I') { if (value[0] != 'I') {
LOG(ERROR) << "Found \"" << str_value << "\" instead of integer option"; LOG(ERROR) << "Found \"" << value << "\" instead of integer option " << name;
return default_value; return default_value;
} }
return to_integer<int64>(str_value.substr(1)); return to_integer<int64>(value.substr(1));
} }
string ConfigShared::get_option_string(Slice name, string default_value) const { string ConfigShared::get_option_string(Slice name, string default_value) const {
auto str_value = get_option(name); auto value = get_option(name);
if (str_value.empty()) { if (value.empty()) {
return default_value; return default_value;
} }
if (str_value[0] != 'S') { if (value[0] != 'S') {
LOG(ERROR) << "Found \"" << str_value << "\" instead of string option"; LOG(ERROR) << "Found \"" << value << "\" instead of string option " << name;
return default_value; return default_value;
} }
return str_value.substr(1); return value.substr(1);
} }
bool ConfigShared::set_option(Slice name, Slice value) { bool ConfigShared::set_option(Slice name, Slice value) {

View File

@ -2924,10 +2924,10 @@ class GetChannelAdministratorsQuery final : public Td::ResultHandler {
}; };
class GetSupportUserQuery final : public Td::ResultHandler { class GetSupportUserQuery final : public Td::ResultHandler {
Promise<Unit> promise_; Promise<UserId> promise_;
public: public:
explicit GetSupportUserQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) { explicit GetSupportUserQuery(Promise<UserId> &&promise) : promise_(std::move(promise)) {
} }
void send() { void send() {
@ -2943,9 +2943,10 @@ class GetSupportUserQuery final : public Td::ResultHandler {
auto ptr = result_ptr.move_as_ok(); auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for GetSupportUserQuery: " << to_string(ptr); LOG(INFO) << "Receive result for GetSupportUserQuery: " << to_string(ptr);
td_->contacts_manager_->on_get_user(std::move(ptr->user_), "GetSupportUserQuery", false, true); auto user_id = ContactsManager::get_user_id(ptr->user_);
td_->contacts_manager_->on_get_user(std::move(ptr->user_), "GetSupportUserQuery", false);
promise_.set_value(Unit()); promise_.set_value(std::move(user_id));
} }
void on_error(Status status) final { void on_error(Status status) final {
@ -4040,6 +4041,7 @@ void ContactsManager::Channel::store(StorerT &storer) const {
STORE_FLAG(is_fake); STORE_FLAG(is_fake);
STORE_FLAG(is_gigagroup); STORE_FLAG(is_gigagroup);
STORE_FLAG(noforwards); STORE_FLAG(noforwards);
STORE_FLAG(can_be_deleted); // 25
END_STORE_FLAGS(); END_STORE_FLAGS();
store(status, storer); store(status, storer);
@ -4110,6 +4112,7 @@ void ContactsManager::Channel::parse(ParserT &parser) {
PARSE_FLAG(is_fake); PARSE_FLAG(is_fake);
PARSE_FLAG(is_gigagroup); PARSE_FLAG(is_gigagroup);
PARSE_FLAG(noforwards); PARSE_FLAG(noforwards);
PARSE_FLAG(can_be_deleted);
END_PARSE_FLAGS(); END_PARSE_FLAGS();
if (use_new_rights) { if (use_new_rights) {
@ -6881,7 +6884,7 @@ void ContactsManager::delete_channel(ChannelId channel_id, Promise<Unit> &&promi
if (c == nullptr) { if (c == nullptr) {
return promise.set_error(Status::Error(400, "Chat info not found")); return promise.set_error(Status::Error(400, "Chat info not found"));
} }
if (!get_channel_can_be_deleted(channel_id)) { if (!get_channel_can_be_deleted(c)) {
return promise.set_error(Status::Error(400, "The chat can't be deleted")); return promise.set_error(Status::Error(400, "The chat can't be deleted"));
} }
@ -8397,8 +8400,7 @@ DialogId ContactsManager::get_dialog_id(const tl_object_ptr<telegram_api::Chat>
return DialogId(get_chat_id(chat)); return DialogId(get_chat_id(chat));
} }
void ContactsManager::on_get_user(tl_object_ptr<telegram_api::User> &&user_ptr, const char *source, bool is_me, void ContactsManager::on_get_user(tl_object_ptr<telegram_api::User> &&user_ptr, const char *source, bool is_me) {
bool expect_support) {
LOG(DEBUG) << "Receive from " << source << ' ' << to_string(user_ptr); LOG(DEBUG) << "Receive from " << source << ' ' << to_string(user_ptr);
int32 constructor_id = user_ptr->get_id(); int32 constructor_id = user_ptr->get_id();
if (constructor_id == telegram_api::userEmpty::ID) { if (constructor_id == telegram_api::userEmpty::ID) {
@ -8440,10 +8442,6 @@ void ContactsManager::on_get_user(tl_object_ptr<telegram_api::User> &&user_ptr,
} }
} }
if (expect_support) {
support_user_id_ = user_id;
}
bool have_access_hash = (flags & USER_FLAG_HAS_ACCESS_HASH) != 0; bool have_access_hash = (flags & USER_FLAG_HAS_ACCESS_HASH) != 0;
bool is_received = (flags & USER_FLAG_IS_INACCESSIBLE) == 0; bool is_received = (flags & USER_FLAG_IS_INACCESSIBLE) == 0;
bool is_contact = (flags & USER_FLAG_IS_CONTACT) != 0; bool is_contact = (flags & USER_FLAG_IS_CONTACT) != 0;
@ -8509,7 +8507,6 @@ void ContactsManager::on_get_user(tl_object_ptr<telegram_api::User> &&user_ptr,
bool need_apply_min_photo = (flags & USER_FLAG_NEED_APPLY_MIN_PHOTO) != 0; bool need_apply_min_photo = (flags & USER_FLAG_NEED_APPLY_MIN_PHOTO) != 0;
bool is_fake = (flags & USER_FLAG_IS_FAKE) != 0; bool is_fake = (flags & USER_FLAG_IS_FAKE) != 0;
LOG_IF(ERROR, !is_support && expect_support) << "Receive non-support " << user_id << ", but expected a support user";
LOG_IF(ERROR, !can_join_groups && !is_bot) LOG_IF(ERROR, !can_join_groups && !is_bot)
<< "Receive not bot " << user_id << " which can't join groups from " << source; << "Receive not bot " << user_id << " which can't join groups from " << source;
LOG_IF(ERROR, can_read_all_group_messages && !is_bot) LOG_IF(ERROR, can_read_all_group_messages && !is_bot)
@ -9960,9 +9957,12 @@ void ContactsManager::on_load_channel_full_from_database(ChannelId channel_id, s
c->participant_count = channel_full->participant_count; c->participant_count = channel_full->participant_count;
c->is_changed = true; c->is_changed = true;
update_channel(c, channel_id);
} }
} }
if (c->can_be_deleted != channel_full->can_be_deleted) {
c->can_be_deleted = channel_full->can_be_deleted;
c->need_save_to_database = true;
}
if (invalidated_channels_full_.erase(channel_id) > 0 || if (invalidated_channels_full_.erase(channel_id) > 0 ||
(!c->is_slow_mode_enabled && channel_full->slow_mode_delay != 0)) { (!c->is_slow_mode_enabled && channel_full->slow_mode_delay != 0)) {
@ -9974,6 +9974,8 @@ void ContactsManager::on_load_channel_full_from_database(ChannelId channel_id, s
send_closure_later(G()->messages_manager(), &MessagesManager::on_dialog_bots_updated, DialogId(channel_id), send_closure_later(G()->messages_manager(), &MessagesManager::on_dialog_bots_updated, DialogId(channel_id),
channel_full->bot_user_ids, true); channel_full->bot_user_ids, true);
update_channel(c, channel_id);
channel_full->is_update_channel_full_sent = true; channel_full->is_update_channel_full_sent = true;
update_channel_full(channel_full, channel_id, "on_load_channel_full_from_database", true); update_channel_full(channel_full, channel_id, "on_load_channel_full_from_database", true);
@ -10876,7 +10878,7 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
on_update_chat_full_invite_link(chat_full, std::move(chat->exported_invite_)); on_update_chat_full_invite_link(chat_full, std::move(chat->exported_invite_));
auto photo = get_photo(td_->file_manager_.get(), std::move(chat->chat_photo_), DialogId(chat_id)); auto photo = get_photo(td_->file_manager_.get(), std::move(chat->chat_photo_), DialogId(chat_id));
// on_update_chat_photo should be a no-op if server sent consistent data // on_update_chat_photo should be a no-op if server sent consistent data
on_update_chat_photo(c, as_dialog_photo(td_->file_manager_.get(), DialogId(chat_id), 0, photo)); on_update_chat_photo(c, chat_id, as_dialog_photo(td_->file_manager_.get(), DialogId(chat_id), 0, photo), false);
on_update_chat_full_photo(chat_full, chat_id, std::move(photo)); on_update_chat_full_photo(chat_full, chat_id, std::move(photo));
if (chat_full->description != chat->about_) { if (chat_full->description != chat->about_) {
chat_full->description = std::move(chat->about_); chat_full->description = std::move(chat->about_);
@ -11049,7 +11051,8 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
auto photo = get_photo(td_->file_manager_.get(), std::move(channel->chat_photo_), DialogId(channel_id)); auto photo = get_photo(td_->file_manager_.get(), std::move(channel->chat_photo_), DialogId(channel_id));
// on_update_channel_photo should be a no-op if server sent consistent data // on_update_channel_photo should be a no-op if server sent consistent data
on_update_channel_photo(c, as_dialog_photo(td_->file_manager_.get(), DialogId(channel_id), c->access_hash, photo)); on_update_channel_photo(
c, channel_id, as_dialog_photo(td_->file_manager_.get(), DialogId(channel_id), c->access_hash, photo), false);
on_update_channel_full_photo(channel_full, channel_id, std::move(photo)); on_update_channel_full_photo(channel_full, channel_id, std::move(photo));
td_->messages_manager_->on_read_channel_outbox(channel_id, td_->messages_manager_->on_read_channel_outbox(channel_id,
@ -11164,6 +11167,10 @@ void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&c
channel_full->can_be_deleted = channel->can_delete_channel_; channel_full->can_be_deleted = channel->can_delete_channel_;
channel_full->need_save_to_database = true; channel_full->need_save_to_database = true;
} }
if (c->can_be_deleted != channel_full->can_be_deleted) {
c->can_be_deleted = channel_full->can_be_deleted;
c->need_save_to_database = true;
}
ChatId migrated_from_chat_id; ChatId migrated_from_chat_id;
MessageId migrated_from_max_message_id; MessageId migrated_from_max_message_id;
@ -11383,7 +11390,7 @@ void ContactsManager::do_update_user_photo(User *u, UserId user_id, ProfilePhoto
u->is_changed = true; u->is_changed = true;
if (invalidate_photo_cache) { if (invalidate_photo_cache) {
drop_user_photos(user_id, u->photo.id <= 0, true, "do_update_user_photo"); drop_user_photos(user_id, !u->photo.small_file_id.is_valid(), true, "do_update_user_photo");
} }
} }
} }
@ -11874,7 +11881,7 @@ void ContactsManager::drop_user_photos(UserId user_id, bool is_empty, bool drop_
user_full->expires_at = 0.0; user_full->expires_at = 0.0;
user_full->need_save_to_database = true; user_full->need_save_to_database = true;
} }
load_user_full(user_id, true, Auto(), "drop_user_photos"); reload_user_full(user_id);
} }
update_user_full(user_full, user_id, "drop_user_photos"); update_user_full(user_full, user_id, "drop_user_photos");
} }
@ -13501,10 +13508,11 @@ void ContactsManager::on_update_chat_participant_count(Chat *c, ChatId chat_id,
void ContactsManager::on_update_chat_photo(Chat *c, ChatId chat_id, void ContactsManager::on_update_chat_photo(Chat *c, ChatId chat_id,
tl_object_ptr<telegram_api::ChatPhoto> &&chat_photo_ptr) { tl_object_ptr<telegram_api::ChatPhoto> &&chat_photo_ptr) {
on_update_chat_photo(c, get_dialog_photo(td_->file_manager_.get(), DialogId(chat_id), 0, std::move(chat_photo_ptr))); on_update_chat_photo(
c, chat_id, get_dialog_photo(td_->file_manager_.get(), DialogId(chat_id), 0, std::move(chat_photo_ptr)), true);
} }
void ContactsManager::on_update_chat_photo(Chat *c, DialogPhoto &&photo) { void ContactsManager::on_update_chat_photo(Chat *c, ChatId chat_id, DialogPhoto &&photo, bool invalidate_photo_cache) {
if (td_->auth_manager_->is_bot()) { if (td_->auth_manager_->is_bot()) {
photo.minithumbnail.clear(); photo.minithumbnail.clear();
} }
@ -13513,6 +13521,20 @@ void ContactsManager::on_update_chat_photo(Chat *c, DialogPhoto &&photo) {
c->photo = std::move(photo); c->photo = std::move(photo);
c->is_photo_changed = true; c->is_photo_changed = true;
c->need_save_to_database = true; c->need_save_to_database = true;
if (invalidate_photo_cache) {
auto chat_full = get_chat_full(chat_id); // must not load ChatFull
if (chat_full != nullptr) {
if (!chat_full->photo.is_empty()) {
chat_full->photo = Photo();
chat_full->is_changed = true;
}
if (c->photo.small_file_id.is_valid()) {
reload_chat_full(chat_id, Auto());
}
update_chat_full(chat_full, chat_id, "on_update_chat_photo");
}
}
} }
} }
@ -13630,10 +13652,13 @@ void ContactsManager::drop_chat_full(ChatId chat_id) {
void ContactsManager::on_update_channel_photo(Channel *c, ChannelId channel_id, void ContactsManager::on_update_channel_photo(Channel *c, ChannelId channel_id,
tl_object_ptr<telegram_api::ChatPhoto> &&chat_photo_ptr) { tl_object_ptr<telegram_api::ChatPhoto> &&chat_photo_ptr) {
on_update_channel_photo( on_update_channel_photo(
c, get_dialog_photo(td_->file_manager_.get(), DialogId(channel_id), c->access_hash, std::move(chat_photo_ptr))); c, channel_id,
get_dialog_photo(td_->file_manager_.get(), DialogId(channel_id), c->access_hash, std::move(chat_photo_ptr)),
true);
} }
void ContactsManager::on_update_channel_photo(Channel *c, DialogPhoto &&photo) { void ContactsManager::on_update_channel_photo(Channel *c, ChannelId channel_id, DialogPhoto &&photo,
bool invalidate_photo_cache) {
if (td_->auth_manager_->is_bot()) { if (td_->auth_manager_->is_bot()) {
photo.minithumbnail.clear(); photo.minithumbnail.clear();
} }
@ -13642,6 +13667,24 @@ void ContactsManager::on_update_channel_photo(Channel *c, DialogPhoto &&photo) {
c->photo = std::move(photo); c->photo = std::move(photo);
c->is_photo_changed = true; c->is_photo_changed = true;
c->need_save_to_database = true; c->need_save_to_database = true;
if (invalidate_photo_cache) {
auto channel_full = get_channel_full(channel_id, true, "on_update_channel_photo"); // must not load ChannelFull
if (channel_full != nullptr) {
if (!channel_full->photo.is_empty()) {
channel_full->photo = Photo();
channel_full->is_changed = true;
}
if (c->photo.small_file_id.is_valid()) {
if (channel_full->expires_at > 0.0) {
channel_full->expires_at = 0.0;
channel_full->need_save_to_database = true;
}
reload_channel_full(channel_id, Auto(), "on_update_channel_photo");
}
update_channel_full(channel_full, channel_id, "on_update_channel_photo");
}
}
} }
} }
@ -14853,6 +14896,18 @@ bool ContactsManager::get_channel_has_linked_channel(const Channel *c) {
return c->has_linked_channel; return c->has_linked_channel;
} }
bool ContactsManager::get_channel_can_be_deleted(ChannelId channel_id) const {
auto c = get_channel(channel_id);
if (c == nullptr) {
return false;
}
return get_channel_can_be_deleted(c);
}
bool ContactsManager::get_channel_can_be_deleted(const Channel *c) {
return c->can_be_deleted;
}
ChannelId ContactsManager::get_channel_linked_channel_id(ChannelId channel_id) { ChannelId ContactsManager::get_channel_linked_channel_id(ChannelId channel_id) {
auto channel_full = get_channel_full_const(channel_id); auto channel_full = get_channel_full_const(channel_id);
if (channel_full == nullptr) { if (channel_full == nullptr) {
@ -14875,17 +14930,6 @@ int32 ContactsManager::get_channel_slow_mode_delay(ChannelId channel_id) {
return channel_full->slow_mode_delay; return channel_full->slow_mode_delay;
} }
bool ContactsManager::get_channel_can_be_deleted(ChannelId channel_id) {
auto channel_full = get_channel_full_const(channel_id);
if (channel_full == nullptr) {
channel_full = get_channel_full_force(channel_id, true, "get_channel_can_be_deleted");
if (channel_full == nullptr) {
return get_channel_status(channel_id).is_creator();
}
}
return channel_full->can_be_deleted;
}
bool ContactsManager::have_channel(ChannelId channel_id) const { bool ContactsManager::have_channel(ChannelId channel_id) const {
return channels_.count(channel_id) > 0; return channels_.count(channel_id) > 0;
} }
@ -15310,6 +15354,7 @@ void ContactsManager::ban_dialog_participant(DialogId dialog_id, DialogId partic
return delete_chat_participant(dialog_id.get_chat_id(), participant_dialog_id.get_user_id(), revoke_messages, return delete_chat_participant(dialog_id.get_chat_id(), participant_dialog_id.get_user_id(), revoke_messages,
std::move(promise)); std::move(promise));
case DialogType::Channel: case DialogType::Channel:
// must use td_api::chatMemberStatusBanned to properly fix banned_until_date
return set_channel_participant_status(dialog_id.get_channel_id(), participant_dialog_id, return set_channel_participant_status(dialog_id.get_channel_id(), participant_dialog_id,
td_api::make_object<td_api::chatMemberStatusBanned>(banned_until_date), td_api::make_object<td_api::chatMemberStatusBanned>(banned_until_date),
std::move(promise)); std::move(promise));
@ -16710,26 +16755,35 @@ tl_object_ptr<td_api::chatInviteLinkInfo> ContactsManager::get_chat_invite_link_
creates_join_request, is_public); creates_join_request, is_public);
} }
UserId ContactsManager::get_support_user(Promise<Unit> &&promise) { void ContactsManager::get_support_user(Promise<td_api::object_ptr<td_api::user>> &&promise) {
if (support_user_id_.is_valid()) { if (support_user_id_.is_valid()) {
promise.set_value(Unit()); return promise.set_value(get_user_object(support_user_id_));
return support_user_id_;
} }
td_->create_handler<GetSupportUserQuery>(std::move(promise))->send(); auto query_promise = PromiseCreator::lambda(
return UserId(); [actor_id = actor_id(this), promise = std::move(promise)](Result<UserId> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
send_closure(actor_id, &ContactsManager::on_get_support_user, result.move_as_ok(), std::move(promise));
}
});
td_->create_handler<GetSupportUserQuery>(std::move(query_promise))->send();
} }
void ContactsManager::after_get_difference() { void ContactsManager::on_get_support_user(UserId user_id, Promise<td_api::object_ptr<td_api::user>> &&promise) {
if (td_->auth_manager_->is_bot()) { TRY_STATUS_PROMISE(promise, G()->close_status());
return;
}
get_user(get_my_id(), 3, Promise<Unit>());
if (td_->is_online()) { const User *u = get_user(user_id);
reload_created_public_dialogs(PublicDialogType::HasUsername, Promise<td_api::object_ptr<td_api::chats>>()); if (u == nullptr) {
reload_created_public_dialogs(PublicDialogType::IsLocationBased, Promise<td_api::object_ptr<td_api::chats>>()); return promise.set_error(Status::Error(500, "Can't find support user"));
} }
if (!u->is_support) {
LOG(ERROR) << "Receive non-support " << user_id << ", but expected a support user";
}
support_user_id_ = user_id;
promise.set_value(get_user_object(user_id, u));
} }
void ContactsManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const { void ContactsManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const {

View File

@ -151,8 +151,7 @@ class ContactsManager final : public Actor {
void reload_contacts(bool force); void reload_contacts(bool force);
void on_get_user(tl_object_ptr<telegram_api::User> &&user, const char *source, bool is_me = false, void on_get_user(tl_object_ptr<telegram_api::User> &&user, const char *source, bool is_me = false);
bool expect_support = false);
void on_get_users(vector<tl_object_ptr<telegram_api::User>> &&users, const char *source); void on_get_users(vector<tl_object_ptr<telegram_api::User>> &&users, const char *source);
void on_binlog_user_event(BinlogEvent &&event); void on_binlog_user_event(BinlogEvent &&event);
@ -441,6 +440,8 @@ class ContactsManager final : public Actor {
void check_created_public_dialogs_limit(PublicDialogType type, Promise<Unit> &&promise); void check_created_public_dialogs_limit(PublicDialogType type, Promise<Unit> &&promise);
void reload_created_public_dialogs(PublicDialogType type, Promise<td_api::object_ptr<td_api::chats>> &&promise);
vector<DialogId> get_dialogs_for_discussion(Promise<Unit> &&promise); vector<DialogId> get_dialogs_for_discussion(Promise<Unit> &&promise);
vector<DialogId> get_inactive_channels(Promise<Unit> &&promise); vector<DialogId> get_inactive_channels(Promise<Unit> &&promise);
@ -535,9 +536,9 @@ class ContactsManager final : public Actor {
int32 get_channel_participant_count(ChannelId channel_id) const; int32 get_channel_participant_count(ChannelId channel_id) const;
bool get_channel_sign_messages(ChannelId channel_id) const; bool get_channel_sign_messages(ChannelId channel_id) const;
bool get_channel_has_linked_channel(ChannelId channel_id) const; bool get_channel_has_linked_channel(ChannelId channel_id) const;
bool get_channel_can_be_deleted(ChannelId channel_id) const;
ChannelId get_channel_linked_channel_id(ChannelId channel_id); ChannelId get_channel_linked_channel_id(ChannelId channel_id);
int32 get_channel_slow_mode_delay(ChannelId channel_id); int32 get_channel_slow_mode_delay(ChannelId channel_id);
bool get_channel_can_be_deleted(ChannelId channel_id);
void add_dialog_participant(DialogId dialog_id, UserId user_id, int32 forward_limit, Promise<Unit> &&promise); void add_dialog_participant(DialogId dialog_id, UserId user_id, int32 forward_limit, Promise<Unit> &&promise);
@ -599,12 +600,10 @@ class ContactsManager final : public Actor {
tl_object_ptr<td_api::chatInviteLinkInfo> get_chat_invite_link_info_object(const string &invite_link); tl_object_ptr<td_api::chatInviteLinkInfo> get_chat_invite_link_info_object(const string &invite_link);
UserId get_support_user(Promise<Unit> &&promise); void get_support_user(Promise<td_api::object_ptr<td_api::user>> &&promise);
void repair_chat_participants(ChatId chat_id); void repair_chat_participants(ChatId chat_id);
void after_get_difference();
void get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const; void get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const;
static tl_object_ptr<td_api::dateRange> convert_date_range( static tl_object_ptr<td_api::dateRange> convert_date_range(
@ -835,6 +834,7 @@ class ContactsManager final : public Actor {
bool sign_messages = false; bool sign_messages = false;
bool is_slow_mode_enabled = false; bool is_slow_mode_enabled = false;
bool noforwards = false; bool noforwards = false;
bool can_be_deleted = false;
bool is_megagroup = false; bool is_megagroup = false;
bool is_gigagroup = false; bool is_gigagroup = false;
@ -1213,6 +1213,7 @@ class ContactsManager final : public Actor {
DialogParticipantStatus get_channel_permissions(const Channel *c) const; DialogParticipantStatus get_channel_permissions(const Channel *c) const;
static bool get_channel_sign_messages(const Channel *c); static bool get_channel_sign_messages(const Channel *c);
static bool get_channel_has_linked_channel(const Channel *c); static bool get_channel_has_linked_channel(const Channel *c);
static bool get_channel_can_be_deleted(const Channel *c);
void set_my_id(UserId my_id); void set_my_id(UserId my_id);
@ -1260,7 +1261,7 @@ class ContactsManager final : public Actor {
void on_update_chat_participant_count(Chat *c, ChatId chat_id, int32 participant_count, int32 version, void on_update_chat_participant_count(Chat *c, ChatId chat_id, int32 participant_count, int32 version,
const string &debug_str); const string &debug_str);
void on_update_chat_photo(Chat *c, ChatId chat_id, tl_object_ptr<telegram_api::ChatPhoto> &&chat_photo_ptr); void on_update_chat_photo(Chat *c, ChatId chat_id, tl_object_ptr<telegram_api::ChatPhoto> &&chat_photo_ptr);
void on_update_chat_photo(Chat *c, DialogPhoto &&photo); void on_update_chat_photo(Chat *c, ChatId chat_id, DialogPhoto &&photo, bool invalidate_photo_cache);
static void on_update_chat_title(Chat *c, ChatId chat_id, string &&title); static void on_update_chat_title(Chat *c, ChatId chat_id, string &&title);
static void on_update_chat_active(Chat *c, ChatId chat_id, bool is_active); static void on_update_chat_active(Chat *c, ChatId chat_id, bool is_active);
static void on_update_chat_migrated_to_channel_id(Chat *c, ChatId chat_id, ChannelId migrated_to_channel_id); static void on_update_chat_migrated_to_channel_id(Chat *c, ChatId chat_id, ChannelId migrated_to_channel_id);
@ -1275,7 +1276,7 @@ class ContactsManager final : public Actor {
void on_update_channel_photo(Channel *c, ChannelId channel_id, void on_update_channel_photo(Channel *c, ChannelId channel_id,
tl_object_ptr<telegram_api::ChatPhoto> &&chat_photo_ptr); tl_object_ptr<telegram_api::ChatPhoto> &&chat_photo_ptr);
void on_update_channel_photo(Channel *c, DialogPhoto &&photo); void on_update_channel_photo(Channel *c, ChannelId channel_id, DialogPhoto &&photo, bool invalidate_photo_cache);
static void on_update_channel_title(Channel *c, ChannelId channel_id, string &&title); static void on_update_channel_title(Channel *c, ChannelId channel_id, string &&title);
void on_update_channel_username(Channel *c, ChannelId channel_id, string &&username); void on_update_channel_username(Channel *c, ChannelId channel_id, string &&username);
void on_update_channel_status(Channel *c, ChannelId channel_id, DialogParticipantStatus &&status); void on_update_channel_status(Channel *c, ChannelId channel_id, DialogParticipantStatus &&status);
@ -1457,8 +1458,6 @@ class ContactsManager final : public Actor {
static void return_created_public_dialogs(Promise<td_api::object_ptr<td_api::chats>> &&promise, static void return_created_public_dialogs(Promise<td_api::object_ptr<td_api::chats>> &&promise,
const vector<ChannelId> &channel_ids); const vector<ChannelId> &channel_ids);
void reload_created_public_dialogs(PublicDialogType type, Promise<td_api::object_ptr<td_api::chats>> &&promise);
void finish_get_created_public_dialogs(PublicDialogType type, Result<Unit> &&result); void finish_get_created_public_dialogs(PublicDialogType type, Result<Unit> &&result);
void update_created_public_channels(Channel *c, ChannelId channel_id); void update_created_public_channels(Channel *c, ChannelId channel_id);
@ -1640,6 +1639,8 @@ class ContactsManager final : public Actor {
void send_load_async_graph_query(DcId dc_id, string token, int64 x, void send_load_async_graph_query(DcId dc_id, string token, int64 x,
Promise<td_api::object_ptr<td_api::StatisticalGraph>> &&promise); Promise<td_api::object_ptr<td_api::StatisticalGraph>> &&promise);
void on_get_support_user(UserId user_id, Promise<td_api::object_ptr<td_api::user>> &&promise);
static void on_user_online_timeout_callback(void *contacts_manager_ptr, int64 user_id_long); static void on_user_online_timeout_callback(void *contacts_manager_ptr, int64 user_id_long);
static void on_channel_unban_timeout_callback(void *contacts_manager_ptr, int64 channel_id_long); static void on_channel_unban_timeout_callback(void *contacts_manager_ptr, int64 channel_id_long);

View File

@ -569,6 +569,20 @@ StringBuilder &operator<<(StringBuilder &string_builder, const DialogParticipant
DialogParticipantStatus get_dialog_participant_status(const td_api::object_ptr<td_api::ChatMemberStatus> &status, DialogParticipantStatus get_dialog_participant_status(const td_api::object_ptr<td_api::ChatMemberStatus> &status,
ChannelType channel_type) { ChannelType channel_type) {
auto constructor_id = status == nullptr ? td_api::chatMemberStatusMember::ID : status->get_id(); auto constructor_id = status == nullptr ? td_api::chatMemberStatusMember::ID : status->get_id();
auto fix_until_date = [](int32 until_date) {
if (until_date == 0) {
// fast path
return 0;
}
// if user is restricted for more than 366 days or less than 30 seconds from the current time,
// they are considered to be restricted forever
auto unix_time = G()->unix_time();
if (until_date < unix_time + 30 || until_date > unix_time + 366 * 86400) {
return 0;
}
return until_date;
};
switch (constructor_id) { switch (constructor_id) {
case td_api::chatMemberStatusCreator::ID: { case td_api::chatMemberStatusCreator::ID: {
auto st = static_cast<const td_api::chatMemberStatusCreator *>(status.get()); auto st = static_cast<const td_api::chatMemberStatusCreator *>(status.get());
@ -592,13 +606,13 @@ DialogParticipantStatus get_dialog_participant_status(const td_api::object_ptr<t
case td_api::chatMemberStatusRestricted::ID: { case td_api::chatMemberStatusRestricted::ID: {
auto st = static_cast<const td_api::chatMemberStatusRestricted *>(status.get()); auto st = static_cast<const td_api::chatMemberStatusRestricted *>(status.get());
return DialogParticipantStatus::Restricted(RestrictedRights(st->permissions_), st->is_member_, return DialogParticipantStatus::Restricted(RestrictedRights(st->permissions_), st->is_member_,
st->restricted_until_date_); fix_until_date(st->restricted_until_date_));
} }
case td_api::chatMemberStatusLeft::ID: case td_api::chatMemberStatusLeft::ID:
return DialogParticipantStatus::Left(); return DialogParticipantStatus::Left();
case td_api::chatMemberStatusBanned::ID: { case td_api::chatMemberStatusBanned::ID: {
auto st = static_cast<const td_api::chatMemberStatusBanned *>(status.get()); auto st = static_cast<const td_api::chatMemberStatusBanned *>(status.get());
return DialogParticipantStatus::Banned(st->banned_until_date_); return DialogParticipantStatus::Banned(fix_until_date(st->banned_until_date_));
} }
default: default:
UNREACHABLE(); UNREACHABLE();

View File

@ -593,8 +593,7 @@ SecretInputMedia DocumentsManager::get_secret_input_media(FileId document_file_i
const GeneralDocument *document = get_document(document_file_id); const GeneralDocument *document = get_document(document_file_id);
CHECK(document != nullptr); CHECK(document != nullptr);
auto file_view = td_->file_manager_->get_file_view(document_file_id); auto file_view = td_->file_manager_->get_file_view(document_file_id);
auto &encryption_key = file_view.encryption_key(); if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty()) {
if (!file_view.is_encrypted_secret() || encryption_key.empty()) {
return SecretInputMedia{}; return SecretInputMedia{};
} }
if (file_view.has_remote_location()) { if (file_view.has_remote_location()) {
@ -610,12 +609,13 @@ SecretInputMedia DocumentsManager::get_secret_input_media(FileId document_file_i
if (!document->file_name.empty()) { if (!document->file_name.empty()) {
attributes.push_back(make_tl_object<secret_api::documentAttributeFilename>(document->file_name)); attributes.push_back(make_tl_object<secret_api::documentAttributeFilename>(document->file_name));
} }
return SecretInputMedia{ return {std::move(input_file),
std::move(input_file), std::move(thumbnail),
make_tl_object<secret_api::decryptedMessageMediaDocument>( document->thumbnail.dimensions,
std::move(thumbnail), document->thumbnail.dimensions.width, document->thumbnail.dimensions.height, document->mime_type,
document->mime_type, narrow_cast<int32>(file_view.size()), BufferSlice(encryption_key.key_slice()), file_view,
BufferSlice(encryption_key.iv_slice()), std::move(attributes), caption)}; std::move(attributes),
caption};
} }
tl_object_ptr<telegram_api::InputMedia> DocumentsManager::get_input_media( tl_object_ptr<telegram_api::InputMedia> DocumentsManager::get_input_media(

View File

@ -1647,7 +1647,11 @@ void GroupCallManager::on_get_group_call_participants(
if (is_load) { if (is_load) {
auto *group_call_participants = add_group_call_participants(input_group_call_id); auto *group_call_participants = add_group_call_participants(input_group_call_id);
if (group_call_participants->next_offset == offset) { if (group_call_participants->next_offset == offset) {
group_call_participants->next_offset = std::move(participants->next_offset_); if (!offset.empty() && participants->next_offset_.empty() && group_call_participants->joined_date_asc) {
LOG(INFO) << "Ignore empty next_offset";
} else {
group_call_participants->next_offset = std::move(participants->next_offset_);
}
} }
if (is_empty || is_sync) { if (is_empty || is_sync) {
@ -1826,6 +1830,8 @@ void GroupCallManager::on_update_group_call_participants(
auto &pending_version_updates = group_call_participants->pending_version_updates_[version].updates; auto &pending_version_updates = group_call_participants->pending_version_updates_[version].updates;
auto &pending_mute_updates = group_call_participants->pending_mute_updates_[version].updates; auto &pending_mute_updates = group_call_participants->pending_mute_updates_[version].updates;
LOG(INFO) << "Have " << pending_version_updates.size() << " versioned and " << pending_mute_updates.size()
<< " mute pending updates for " << input_group_call_id;
for (auto &group_call_participant : participants) { for (auto &group_call_participant : participants) {
GroupCallParticipant participant(group_call_participant, version); GroupCallParticipant participant(group_call_participant, version);
if (!participant.is_valid()) { if (!participant.is_valid()) {
@ -1879,6 +1885,9 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup
auto &pending_version_updates = participants_it->second->pending_version_updates_; auto &pending_version_updates = participants_it->second->pending_version_updates_;
auto &pending_mute_updates = participants_it->second->pending_mute_updates_; auto &pending_mute_updates = participants_it->second->pending_mute_updates_;
LOG(INFO) << "Process " << pending_version_updates.size() << " versioned and " << pending_mute_updates.size()
<< " mute updates for " << input_group_call_id;
auto process_mute_updates = [&] { auto process_mute_updates = [&] {
while (!pending_mute_updates.empty()) { while (!pending_mute_updates.empty()) {
auto it = pending_mute_updates.begin(); auto it = pending_mute_updates.begin();
@ -2036,7 +2045,7 @@ void GroupCallManager::on_sync_group_call_participants(InputGroupCallId input_gr
GroupCallParticipantOrder GroupCallManager::get_real_participant_order(bool can_self_unmute, GroupCallParticipantOrder GroupCallManager::get_real_participant_order(bool can_self_unmute,
const GroupCallParticipant &participant, const GroupCallParticipant &participant,
const GroupCallParticipants *participants) { const GroupCallParticipants *participants) {
auto real_order = participant.get_real_order(can_self_unmute, participants->joined_date_asc, false); auto real_order = participant.get_real_order(can_self_unmute, participants->joined_date_asc);
if (real_order >= participants->min_order) { if (real_order >= participants->min_order) {
return real_order; return real_order;
} }
@ -2106,7 +2115,7 @@ void GroupCallManager::process_group_call_participants(
} }
if (is_load) { if (is_load) {
auto real_order = participant.get_real_order(can_self_unmute, joined_date_asc, true); auto real_order = participant.get_server_order(can_self_unmute, joined_date_asc);
if (real_order > min_order) { if (real_order > min_order) {
LOG(ERROR) << "Receive group call participant " << participant.dialog_id << " with order " << real_order LOG(ERROR) << "Receive group call participant " << participant.dialog_id << " with order " << real_order
<< " after group call participant " << debug_min_order_dialog_id << " with order " << min_order; << " after group call participant " << debug_min_order_dialog_id << " with order " << min_order;
@ -4122,7 +4131,11 @@ void GroupCallManager::on_group_call_left_impl(GroupCall *group_call, bool need_
auto input_group_call_id = get_input_group_call_id(group_call->group_call_id).ok(); auto input_group_call_id = get_input_group_call_id(group_call->group_call_id).ok();
try_clear_group_call_participants(input_group_call_id); try_clear_group_call_participants(input_group_call_id);
if (!group_call->need_rejoin) { if (!group_call->need_rejoin) {
process_group_call_after_join_requests(input_group_call_id, "on_group_call_left_impl"); if (is_group_call_being_joined(input_group_call_id)) {
LOG(ERROR) << "Left a being joined group call. Did you change audio_source_id without leaving the group call?";
} else {
process_group_call_after_join_requests(input_group_call_id, "on_group_call_left_impl");
}
} }
} }

View File

@ -75,10 +75,16 @@ bool GroupCallParticipant::is_versioned_update(const tl_object_ptr<telegram_api:
return participant->just_joined_ || participant->left_ || participant->versioned_; return participant->just_joined_ || participant->left_ || participant->versioned_;
} }
GroupCallParticipantOrder GroupCallParticipant::get_real_order(bool can_self_unmute, bool joined_date_asc, GroupCallParticipantOrder GroupCallParticipant::get_real_order(bool can_self_unmute, bool joined_date_asc) const {
bool keep_active_date) const {
auto sort_active_date = td::max(active_date, local_active_date); auto sort_active_date = td::max(active_date, local_active_date);
if (!keep_active_date && sort_active_date < G()->unix_time() - 300) { if (sort_active_date == 0 && !get_is_muted_by_admin()) { // if the participant isn't muted by admin
if (get_is_muted_by_themselves()) {
sort_active_date = joined_date;
} else {
sort_active_date = G()->unix_time();
}
}
if (sort_active_date < G()->unix_time() - 300) {
sort_active_date = 0; sort_active_date = 0;
} }
auto sort_raise_hand_rating = can_self_unmute ? raise_hand_rating : 0; auto sort_raise_hand_rating = can_self_unmute ? raise_hand_rating : 0;
@ -87,6 +93,21 @@ GroupCallParticipantOrder GroupCallParticipant::get_real_order(bool can_self_unm
return GroupCallParticipantOrder(has_video, sort_active_date, sort_raise_hand_rating, sort_joined_date); return GroupCallParticipantOrder(has_video, sort_active_date, sort_raise_hand_rating, sort_joined_date);
} }
GroupCallParticipantOrder GroupCallParticipant::get_server_order(bool can_self_unmute, bool joined_date_asc) const {
auto sort_active_date = active_date;
if (sort_active_date == 0 && !server_is_muted_by_admin) { // if the participant isn't muted by admin
if (server_is_muted_by_themselves) {
sort_active_date = joined_date;
} else {
sort_active_date = G()->unix_time();
}
}
auto sort_raise_hand_rating = can_self_unmute ? raise_hand_rating : 0;
auto sort_joined_date = joined_date_asc ? std::numeric_limits<int32>::max() - joined_date : joined_date;
bool has_video = !video_payload.is_empty() || !presentation_payload.is_empty();
return GroupCallParticipantOrder(has_video, sort_active_date, sort_raise_hand_rating, sort_joined_date);
}
bool GroupCallParticipant::get_is_muted_by_themselves() const { bool GroupCallParticipant::get_is_muted_by_themselves() const {
return have_pending_is_muted ? pending_is_muted_by_themselves : server_is_muted_by_themselves; return have_pending_is_muted ? pending_is_muted_by_themselves : server_is_muted_by_themselves;
} }

View File

@ -78,7 +78,9 @@ struct GroupCallParticipant {
bool set_pending_is_muted(bool is_muted, bool can_manage, bool is_admin); bool set_pending_is_muted(bool is_muted, bool can_manage, bool is_admin);
GroupCallParticipantOrder get_real_order(bool can_self_unmute, bool joined_date_asc, bool keep_active_date) const; GroupCallParticipantOrder get_real_order(bool can_self_unmute, bool joined_date_asc) const;
GroupCallParticipantOrder get_server_order(bool can_self_unmute, bool joined_date_asc) const;
bool is_valid() const { bool is_valid() const {
return dialog_id.is_valid(); return dialog_id.is_valid();

View File

@ -667,7 +667,7 @@ class MessageDice final : public MessageContent {
MessageDice() = default; MessageDice() = default;
MessageDice(const string &emoji, int32 dice_value) MessageDice(const string &emoji, int32 dice_value)
: emoji(emoji.empty() ? string(DEFAULT_EMOJI) : remove_emoji_modifiers(emoji).str()), dice_value(dice_value) { : emoji(emoji.empty() ? string(DEFAULT_EMOJI) : remove_emoji_modifiers(emoji)), dice_value(dice_value) {
} }
MessageContentType get_type() const final { MessageContentType get_type() const final {
@ -2100,10 +2100,10 @@ Result<InputMessageContent> get_input_message_content(
std::move(thumbnail), std::move(sticker_file_ids)); std::move(thumbnail), std::move(sticker_file_ids));
} }
bool can_have_input_media(const Td *td, const MessageContent *content) { bool can_have_input_media(const Td *td, const MessageContent *content, bool is_server) {
switch (content->get_type()) { switch (content->get_type()) {
case MessageContentType::Game: case MessageContentType::Game:
return static_cast<const MessageGame *>(content)->game.has_input_media(); return is_server || static_cast<const MessageGame *>(content)->game.has_input_media();
case MessageContentType::Poll: case MessageContentType::Poll:
return td->poll_manager_->has_input_media(static_cast<const MessagePoll *>(content)->poll_id); return td->poll_manager_->has_input_media(static_cast<const MessagePoll *>(content)->poll_id);
case MessageContentType::Unsupported: case MessageContentType::Unsupported:
@ -2264,7 +2264,7 @@ SecretInputMedia get_secret_input_media(const MessageContent *content, Td *td,
static tl_object_ptr<telegram_api::InputMedia> get_input_media_impl( static tl_object_ptr<telegram_api::InputMedia> get_input_media_impl(
const MessageContent *content, Td *td, tl_object_ptr<telegram_api::InputFile> input_file, const MessageContent *content, Td *td, tl_object_ptr<telegram_api::InputFile> input_file,
tl_object_ptr<telegram_api::InputFile> input_thumbnail, int32 ttl, const string &emoji) { tl_object_ptr<telegram_api::InputFile> input_thumbnail, int32 ttl, const string &emoji) {
if (!can_have_input_media(td, content)) { if (!can_have_input_media(td, content, false)) {
return nullptr; return nullptr;
} }
switch (content->get_type()) { switch (content->get_type()) {
@ -4358,10 +4358,10 @@ unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const
MessageContentDupType type, MessageCopyOptions &&copy_options) { MessageContentDupType type, MessageCopyOptions &&copy_options) {
CHECK(content != nullptr); CHECK(content != nullptr);
if (copy_options.send_copy) { if (copy_options.send_copy) {
CHECK(type == MessageContentDupType::Copy); CHECK(type == MessageContentDupType::Copy || type == MessageContentDupType::ServerCopy);
} }
if (type != MessageContentDupType::Forward && type != MessageContentDupType::SendViaBot && if (type != MessageContentDupType::Forward && type != MessageContentDupType::SendViaBot &&
!can_have_input_media(td, content)) { !can_have_input_media(td, content, type == MessageContentDupType::ServerCopy)) {
return nullptr; return nullptr;
} }
@ -4382,7 +4382,8 @@ unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const
if (to_secret) { if (to_secret) {
thumbnail_file_id = get_message_content_thumbnail_file_id(content, td); thumbnail_file_id = get_message_content_thumbnail_file_id(content, td);
} }
auto replace_caption = type == MessageContentDupType::Copy && copy_options.replace_caption; auto replace_caption = (type == MessageContentDupType::Copy || type == MessageContentDupType::ServerCopy) &&
copy_options.replace_caption;
switch (content->get_type()) { switch (content->get_type()) {
case MessageContentType::Animation: { case MessageContentType::Animation: {
auto result = make_unique<MessageAnimation>(*static_cast<const MessageAnimation *>(content)); auto result = make_unique<MessageAnimation>(*static_cast<const MessageAnimation *>(content));
@ -4512,7 +4513,7 @@ unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const
return std::move(result); return std::move(result);
} }
case MessageContentType::Poll: case MessageContentType::Poll:
if (type == MessageContentDupType::Copy) { if (type == MessageContentDupType::Copy || type == MessageContentDupType::ServerCopy) {
return make_unique<MessagePoll>( return make_unique<MessagePoll>(
td->poll_manager_->dup_poll(static_cast<const MessagePoll *>(content)->poll_id)); td->poll_manager_->dup_poll(static_cast<const MessagePoll *>(content)->poll_id));
} else { } else {
@ -5505,17 +5506,17 @@ void get_message_content_animated_emoji_click_sticker(const MessageContent *cont
} }
void on_message_content_animated_emoji_clicked(const MessageContent *content, FullMessageId full_message_id, Td *td, void on_message_content_animated_emoji_clicked(const MessageContent *content, FullMessageId full_message_id, Td *td,
Slice emoji, string data) { string &&emoji, string &&data) {
if (content->get_type() != MessageContentType::Text) { if (content->get_type() != MessageContentType::Text) {
return; return;
} }
emoji = remove_emoji_modifiers(emoji); remove_emoji_modifiers_in_place(emoji);
auto &text = static_cast<const MessageText *>(content)->text; auto &text = static_cast<const MessageText *>(content)->text;
if (!text.entities.empty() || remove_emoji_modifiers(text.text) != emoji) { if (!text.entities.empty() || remove_emoji_modifiers(text.text) != emoji) {
return; return;
} }
auto error = td->stickers_manager_->on_animated_emoji_message_clicked(emoji, full_message_id, data); auto error = td->stickers_manager_->on_animated_emoji_message_clicked(std::move(emoji), full_message_id, data);
if (error.is_error()) { if (error.is_error()) {
LOG(WARNING) << "Failed to process animated emoji click with data \"" << data << "\": " << error; LOG(WARNING) << "Failed to process animated emoji click with data \"" << data << "\": " << error;
} }

View File

@ -105,7 +105,7 @@ unique_ptr<MessageContent> create_chat_set_ttl_message_content(int32 ttl);
Result<InputMessageContent> get_input_message_content( Result<InputMessageContent> get_input_message_content(
DialogId dialog_id, tl_object_ptr<td_api::InputMessageContent> &&input_message_content, Td *td); DialogId dialog_id, tl_object_ptr<td_api::InputMessageContent> &&input_message_content, Td *td);
bool can_have_input_media(const Td *td, const MessageContent *content); bool can_have_input_media(const Td *td, const MessageContent *content, bool is_server);
SecretInputMedia get_secret_input_media(const MessageContent *content, Td *td, SecretInputMedia get_secret_input_media(const MessageContent *content, Td *td,
tl_object_ptr<telegram_api::InputEncryptedFile> input_file, tl_object_ptr<telegram_api::InputEncryptedFile> input_file,
@ -192,7 +192,7 @@ unique_ptr<MessageContent> get_message_content(Td *td, FormattedText message_tex
DialogId owner_dialog_id, bool is_content_read, UserId via_bot_user_id, DialogId owner_dialog_id, bool is_content_read, UserId via_bot_user_id,
int32 *ttl, bool *disable_web_page_preview); int32 *ttl, bool *disable_web_page_preview);
enum class MessageContentDupType : int32 { Send, SendViaBot, Forward, Copy }; enum class MessageContentDupType : int32 { Send, SendViaBot, Forward, Copy, ServerCopy };
unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const MessageContent *content, unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const MessageContent *content,
MessageContentDupType type, MessageCopyOptions &&copy_options); MessageContentDupType type, MessageCopyOptions &&copy_options);
@ -232,7 +232,7 @@ void get_message_content_animated_emoji_click_sticker(const MessageContent *cont
Td *td, Promise<td_api::object_ptr<td_api::sticker>> &&promise); Td *td, Promise<td_api::object_ptr<td_api::sticker>> &&promise);
void on_message_content_animated_emoji_clicked(const MessageContent *content, FullMessageId full_message_id, Td *td, void on_message_content_animated_emoji_clicked(const MessageContent *content, FullMessageId full_message_id, Td *td,
Slice emoji, string data); string &&emoji, string &&data);
bool need_reget_message_content(const MessageContent *content); bool need_reget_message_content(const MessageContent *content);

View File

@ -26,6 +26,17 @@ struct MessageCopyOptions {
MessageCopyOptions() = default; MessageCopyOptions() = default;
MessageCopyOptions(bool send_copy, bool remove_caption) : send_copy(send_copy), replace_caption(remove_caption) { MessageCopyOptions(bool send_copy, bool remove_caption) : send_copy(send_copy), replace_caption(remove_caption) {
} }
bool is_supported_server_side() const {
if (!send_copy) {
return true;
}
if ((replace_caption && !new_caption.text.empty()) || top_thread_message_id.is_valid() ||
reply_to_message_id.is_valid() || reply_markup != nullptr) {
return false;
}
return true;
}
}; };
inline StringBuilder &operator<<(StringBuilder &string_builder, MessageCopyOptions copy_options) { inline StringBuilder &operator<<(StringBuilder &string_builder, MessageCopyOptions copy_options) {

View File

@ -4545,8 +4545,6 @@ class ResolveUsernameQuery final : public Td::ResultHandler {
class MessagesManager::UploadMediaCallback final : public FileManager::UploadCallback { class MessagesManager::UploadMediaCallback final : public FileManager::UploadCallback {
public: public:
void on_progress(FileId file_id) final {
}
void on_upload_ok(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) final { void on_upload_ok(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) final {
send_closure_later(G()->messages_manager(), &MessagesManager::on_upload_media, file_id, std::move(input_file), send_closure_later(G()->messages_manager(), &MessagesManager::on_upload_media, file_id, std::move(input_file),
nullptr); nullptr);
@ -7453,8 +7451,8 @@ void MessagesManager::on_dialog_action(DialogId dialog_id, MessageId top_thread_
FullMessageId full_message_id{dialog_id, MessageId(ServerMessageId(clicking_info.message_id))}; FullMessageId full_message_id{dialog_id, MessageId(ServerMessageId(clicking_info.message_id))};
auto *m = get_message_force(full_message_id, "on_dialog_action"); auto *m = get_message_force(full_message_id, "on_dialog_action");
if (m != nullptr) { if (m != nullptr) {
on_message_content_animated_emoji_clicked(m->content.get(), full_message_id, td_, clicking_info.emoji, on_message_content_animated_emoji_clicked(m->content.get(), full_message_id, td_,
std::move(clicking_info.data)); std::move(clicking_info.emoji), std::move(clicking_info.data));
} }
} }
return; return;
@ -9612,8 +9610,8 @@ void MessagesManager::on_get_messages(vector<tl_object_ptr<telegram_api::Message
bool is_scheduled, Promise<Unit> &&promise, const char *source) { bool is_scheduled, Promise<Unit> &&promise, const char *source) {
TRY_STATUS_PROMISE(promise, G()->close_status()); TRY_STATUS_PROMISE(promise, G()->close_status());
LOG(DEBUG) << "Receive " << messages.size() << " messages";
for (auto &message : messages) { for (auto &message : messages) {
LOG(INFO) << "Receive " << to_string(message);
on_get_message(std::move(message), false, is_channel_message, is_scheduled, false, false, source); on_get_message(std::move(message), false, is_channel_message, is_scheduled, false, false, source);
} }
promise.set_value(Unit()); promise.set_value(Unit());
@ -15138,7 +15136,7 @@ void MessagesManager::remove_dialog_mention_notifications(Dialog *d) {
CHECK(m != nullptr); CHECK(m != nullptr);
CHECK(m->message_id.is_valid()); CHECK(m->message_id.is_valid());
if (m->notification_id.is_valid() && is_message_notification_active(d, m) && if (m->notification_id.is_valid() && is_message_notification_active(d, m) &&
is_from_mention_notification_group(d, m)) { is_from_mention_notification_group(m)) {
removed_notification_ids_set.insert(m->notification_id); removed_notification_ids_set.insert(m->notification_id);
} }
} }
@ -15150,7 +15148,7 @@ void MessagesManager::remove_dialog_mention_notifications(Dialog *d) {
if (message_id != d->pinned_message_notification_message_id) { if (message_id != d->pinned_message_notification_message_id) {
auto m = get_message_force(d, message_id, "remove_dialog_mention_notifications"); auto m = get_message_force(d, message_id, "remove_dialog_mention_notifications");
if (m != nullptr && m->notification_id.is_valid() && is_message_notification_active(d, m)) { if (m != nullptr && m->notification_id.is_valid() && is_message_notification_active(d, m)) {
CHECK(is_from_mention_notification_group(d, m)); CHECK(is_from_mention_notification_group(m));
removed_notification_ids_set.insert(m->notification_id); removed_notification_ids_set.insert(m->notification_id);
} }
} }
@ -15846,7 +15844,7 @@ void MessagesManager::remove_message_notification_id(Dialog *d, Message *m, bool
return; return;
} }
auto from_mentions = is_from_mention_notification_group(d, m); auto from_mentions = is_from_mention_notification_group(m);
auto &group_info = get_notification_group_info(d, m); auto &group_info = get_notification_group_info(d, m);
if (!group_info.group_id.is_valid()) { if (!group_info.group_id.is_valid()) {
return; return;
@ -15913,7 +15911,7 @@ void MessagesManager::fix_dialog_last_notification_id(Dialog *d, bool from_menti
if (*it != nullptr && ((*it)->message_id == message_id || (*it)->have_next)) { if (*it != nullptr && ((*it)->message_id == message_id || (*it)->have_next)) {
while (*it != nullptr) { while (*it != nullptr) {
const Message *m = *it; const Message *m = *it;
if (is_from_mention_notification_group(d, m) == from_mentions && m->notification_id.is_valid() && if (is_from_mention_notification_group(m) == from_mentions && m->notification_id.is_valid() &&
is_message_notification_active(d, m) && m->message_id != message_id) { is_message_notification_active(d, m) && m->message_id != message_id) {
bool is_fixed = set_dialog_last_notification(d->dialog_id, group_info, m->date, m->notification_id, bool is_fixed = set_dialog_last_notification(d->dialog_id, group_info, m->date, m->notification_id,
"fix_dialog_last_notification_id"); "fix_dialog_last_notification_id");
@ -26567,7 +26565,7 @@ bool MessagesManager::can_resend_message(const Message *m) const {
auto content_type = m->content->get_type(); auto content_type = m->content->get_type();
if (m->via_bot_user_id.is_valid() || m->hide_via_bot) { if (m->via_bot_user_id.is_valid() || m->hide_via_bot) {
// via bot message // via bot message
if (!can_have_input_media(td_, m->content.get())) { if (!can_have_input_media(td_, m->content.get(), false)) {
return false; return false;
} }
@ -27737,10 +27735,16 @@ class MessagesManager::ForwardMessagesLogEvent {
DialogId from_dialog_id; DialogId from_dialog_id;
vector<MessageId> message_ids; vector<MessageId> message_ids;
vector<Message *> messages_in; vector<Message *> messages_in;
bool drop_author;
bool drop_media_captions;
vector<unique_ptr<Message>> messages_out; vector<unique_ptr<Message>> messages_out;
template <class StorerT> template <class StorerT>
void store(StorerT &storer) const { void store(StorerT &storer) const {
BEGIN_STORE_FLAGS();
STORE_FLAG(drop_author);
STORE_FLAG(drop_media_captions);
END_STORE_FLAGS();
td::store(to_dialog_id, storer); td::store(to_dialog_id, storer);
td::store(from_dialog_id, storer); td::store(from_dialog_id, storer);
td::store(message_ids, storer); td::store(message_ids, storer);
@ -27749,6 +27753,12 @@ class MessagesManager::ForwardMessagesLogEvent {
template <class ParserT> template <class ParserT>
void parse(ParserT &parser) { void parse(ParserT &parser) {
if (parser.version() >= static_cast<int32>(Version::UseServerForwardAsCopy)) {
BEGIN_PARSE_FLAGS();
PARSE_FLAG(drop_author);
PARSE_FLAG(drop_media_captions);
END_PARSE_FLAGS();
}
td::parse(to_dialog_id, parser); td::parse(to_dialog_id, parser);
td::parse(from_dialog_id, parser); td::parse(from_dialog_id, parser);
td::parse(message_ids, parser); td::parse(message_ids, parser);
@ -27758,15 +27768,17 @@ class MessagesManager::ForwardMessagesLogEvent {
uint64 MessagesManager::save_forward_messages_log_event(DialogId to_dialog_id, DialogId from_dialog_id, uint64 MessagesManager::save_forward_messages_log_event(DialogId to_dialog_id, DialogId from_dialog_id,
const vector<Message *> &messages, const vector<Message *> &messages,
const vector<MessageId> &message_ids) { const vector<MessageId> &message_ids, bool drop_author,
ForwardMessagesLogEvent log_event{to_dialog_id, from_dialog_id, message_ids, messages, Auto()}; bool drop_media_captions) {
ForwardMessagesLogEvent log_event{to_dialog_id, from_dialog_id, message_ids, messages,
drop_author, drop_media_captions, Auto()};
return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::ForwardMessages, return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::ForwardMessages,
get_log_event_storer(log_event)); get_log_event_storer(log_event));
} }
void MessagesManager::do_forward_messages(DialogId to_dialog_id, DialogId from_dialog_id, void MessagesManager::do_forward_messages(DialogId to_dialog_id, DialogId from_dialog_id,
const vector<Message *> &messages, const vector<MessageId> &message_ids, const vector<Message *> &messages, const vector<MessageId> &message_ids,
uint64 log_event_id) { bool drop_author, bool drop_media_captions, uint64 log_event_id) {
CHECK(messages.size() == message_ids.size()); CHECK(messages.size() == message_ids.size());
if (messages.empty()) { if (messages.empty()) {
return; return;
@ -27776,7 +27788,8 @@ void MessagesManager::do_forward_messages(DialogId to_dialog_id, DialogId from_d
} }
if (log_event_id == 0 && G()->parameters().use_message_db) { if (log_event_id == 0 && G()->parameters().use_message_db) {
log_event_id = save_forward_messages_log_event(to_dialog_id, from_dialog_id, messages, message_ids); log_event_id = save_forward_messages_log_event(to_dialog_id, from_dialog_id, messages, message_ids, drop_author,
drop_media_captions);
} }
auto schedule_date = get_message_schedule_date(messages[0]); auto schedule_date = get_message_schedule_date(messages[0]);
@ -27801,6 +27814,12 @@ void MessagesManager::do_forward_messages(DialogId to_dialog_id, DialogId from_d
if (messages[0]->noforwards) { if (messages[0]->noforwards) {
flags |= SEND_MESSAGE_FLAG_NOFORWARDS; flags |= SEND_MESSAGE_FLAG_NOFORWARDS;
} }
if (drop_author) {
flags |= telegram_api::messages_forwardMessages::DROP_AUTHOR_MASK;
}
if (drop_media_captions) {
flags |= telegram_api::messages_forwardMessages::DROP_MEDIA_CAPTIONS_MASK;
}
vector<int64> random_ids = vector<int64> random_ids =
transform(messages, [this, to_dialog_id](const Message *m) { return begin_send_message(to_dialog_id, m); }); transform(messages, [this, to_dialog_id](const Message *m) { return begin_send_message(to_dialog_id, m); });
@ -27873,10 +27892,13 @@ unique_ptr<MessagesManager::MessageForwardInfo> MessagesManager::create_message_
} }
void MessagesManager::fix_forwarded_message(Message *m, DialogId to_dialog_id, const Message *forwarded_message, void MessagesManager::fix_forwarded_message(Message *m, DialogId to_dialog_id, const Message *forwarded_message,
int64 media_album_id) const { int64 media_album_id, bool drop_author) const {
m->via_bot_user_id = forwarded_message->via_bot_user_id; bool is_game = m->content->get_type() == MessageContentType::Game;
if (!drop_author || is_game) {
m->via_bot_user_id = forwarded_message->via_bot_user_id;
}
m->media_album_id = media_album_id; m->media_album_id = media_album_id;
if (forwarded_message->view_count > 0 && m->forward_info != nullptr && m->view_count == 0 && if (!drop_author && forwarded_message->view_count > 0 && m->forward_info != nullptr && m->view_count == 0 &&
!(m->message_id.is_scheduled() && is_broadcast_channel(to_dialog_id))) { !(m->message_id.is_scheduled() && is_broadcast_channel(to_dialog_id))) {
m->view_count = forwarded_message->view_count; m->view_count = forwarded_message->view_count;
m->forward_count = forwarded_message->forward_count; m->forward_count = forwarded_message->forward_count;
@ -27987,12 +28009,23 @@ Result<MessagesManager::ForwardedMessages> MessagesManager::get_forwarded_messag
bool to_secret = to_dialog_id.get_type() == DialogType::SecretChat; bool to_secret = to_dialog_id.get_type() == DialogType::SecretChat;
bool can_use_server_forward = !to_secret;
for (auto &copy_option : copy_options) {
if (!copy_option.is_supported_server_side()) {
can_use_server_forward = false;
break;
}
}
CHECK(can_use_server_forward || copy_options.size() == 1);
ForwardedMessages result; ForwardedMessages result;
result.to_dialog = to_dialog; result.to_dialog = to_dialog;
result.from_dialog = from_dialog; result.from_dialog = from_dialog;
result.message_send_options = message_send_options; result.message_send_options = message_send_options;
auto &copied_messages = result.copied_messages; auto &copied_messages = result.copied_messages;
auto &forwarded_message_contents = result.forwarded_message_contents; auto &forwarded_message_contents = result.forwarded_message_contents;
result.drop_author = can_use_server_forward && copy_options[0].send_copy;
result.drop_media_captions = can_use_server_forward && copy_options[0].replace_caption;
std::unordered_map<int64, std::pair<int64, int32>> new_copied_media_album_ids; std::unordered_map<int64, std::pair<int64, int32>> new_copied_media_album_ids;
std::unordered_map<int64, std::pair<int64, int32>> new_forwarded_media_album_ids; std::unordered_map<int64, std::pair<int64, int32>> new_forwarded_media_album_ids;
@ -28014,25 +28047,28 @@ Result<MessagesManager::ForwardedMessages> MessagesManager::get_forwarded_messag
} }
bool need_copy = !message_id.is_server() || to_secret || copy_options[i].send_copy; bool need_copy = !message_id.is_server() || to_secret || copy_options[i].send_copy;
bool is_local_copy = need_copy && !(message_id.is_server() && can_use_server_forward &&
forwarded_message->content->get_type() != MessageContentType::Dice);
if (!(need_copy && td_->auth_manager_->is_bot()) && !can_save_message(from_dialog_id, forwarded_message)) { if (!(need_copy && td_->auth_manager_->is_bot()) && !can_save_message(from_dialog_id, forwarded_message)) {
LOG(INFO) << "Forward of " << message_id << " is restricted"; LOG(INFO) << "Forward of " << message_id << " is restricted";
continue; continue;
} }
auto type = need_copy ? MessageContentDupType::Copy : MessageContentDupType::Forward; auto type = need_copy ? (is_local_copy ? MessageContentDupType::Copy : MessageContentDupType::ServerCopy)
: MessageContentDupType::Forward;
auto top_thread_message_id = copy_options[i].top_thread_message_id; auto top_thread_message_id = copy_options[i].top_thread_message_id;
auto reply_to_message_id = copy_options[i].reply_to_message_id; auto reply_to_message_id = copy_options[i].reply_to_message_id;
auto reply_markup = std::move(copy_options[i].reply_markup); auto reply_markup = std::move(copy_options[i].reply_markup);
unique_ptr<MessageContent> content = unique_ptr<MessageContent> content =
dup_message_content(td_, to_dialog_id, forwarded_message->content.get(), type, std::move(copy_options[i])); dup_message_content(td_, to_dialog_id, forwarded_message->content.get(), type, std::move(copy_options[i]));
if (content == nullptr) { if (content == nullptr) {
LOG(INFO) << "Can't forward " << message_id; LOG(INFO) << "Can't forward content of " << message_id;
continue; continue;
} }
reply_to_message_id = get_reply_to_message_id(to_dialog, top_thread_message_id, reply_to_message_id, false); reply_to_message_id = get_reply_to_message_id(to_dialog, top_thread_message_id, reply_to_message_id, false);
auto can_send_status = can_send_message_content(to_dialog_id, content.get(), !need_copy, td_); auto can_send_status = can_send_message_content(to_dialog_id, content.get(), !is_local_copy, td_);
if (can_send_status.is_error()) { if (can_send_status.is_error()) {
LOG(INFO) << "Can't forward " << message_id << ": " << can_send_status.message(); LOG(INFO) << "Can't forward " << message_id << ": " << can_send_status.message();
continue; continue;
@ -28050,8 +28086,8 @@ Result<MessagesManager::ForwardedMessages> MessagesManager::get_forwarded_messag
} }
if (forwarded_message->media_album_id != 0) { if (forwarded_message->media_album_id != 0) {
auto &new_media_album_id = need_copy ? new_copied_media_album_ids[forwarded_message->media_album_id] auto &new_media_album_id = is_local_copy ? new_copied_media_album_ids[forwarded_message->media_album_id]
: new_forwarded_media_album_ids[forwarded_message->media_album_id]; : new_forwarded_media_album_ids[forwarded_message->media_album_id];
new_media_album_id.second++; new_media_album_id.second++;
if (new_media_album_id.second == 2) { // have at least 2 messages in the new album if (new_media_album_id.second == 2) { // have at least 2 messages in the new album
CHECK(new_media_album_id.first == 0); CHECK(new_media_album_id.first == 0);
@ -28063,7 +28099,7 @@ Result<MessagesManager::ForwardedMessages> MessagesManager::get_forwarded_messag
} }
} }
if (need_copy) { if (is_local_copy) {
copied_messages.push_back({std::move(content), top_thread_message_id, reply_to_message_id, copied_messages.push_back({std::move(content), top_thread_message_id, reply_to_message_id,
std::move(reply_markup), forwarded_message->media_album_id, std::move(reply_markup), forwarded_message->media_album_id,
get_message_disable_web_page_preview(forwarded_message), i}); get_message_disable_web_page_preview(forwarded_message), i});
@ -28123,6 +28159,8 @@ Result<td_api::object_ptr<td_api::messages>> MessagesManager::forward_messages(
auto message_send_options = forwarded_messages_info.message_send_options; auto message_send_options = forwarded_messages_info.message_send_options;
auto &copied_messages = forwarded_messages_info.copied_messages; auto &copied_messages = forwarded_messages_info.copied_messages;
auto &forwarded_message_contents = forwarded_messages_info.forwarded_message_contents; auto &forwarded_message_contents = forwarded_messages_info.forwarded_message_contents;
auto drop_author = forwarded_messages_info.drop_author;
auto drop_media_captions = forwarded_messages_info.drop_media_captions;
vector<td_api::object_ptr<td_api::message>> result(message_ids.size()); vector<td_api::object_ptr<td_api::message>> result(message_ids.size());
vector<Message *> forwarded_messages; vector<Message *> forwarded_messages;
@ -28134,7 +28172,8 @@ Result<td_api::object_ptr<td_api::messages>> MessagesManager::forward_messages(
CHECK(forwarded_message != nullptr); CHECK(forwarded_message != nullptr);
auto content = std::move(forwarded_message_contents[j].content); auto content = std::move(forwarded_message_contents[j].content);
auto forward_info = create_message_forward_info(from_dialog_id, to_dialog_id, forwarded_message); auto forward_info =
drop_author ? nullptr : create_message_forward_info(from_dialog_id, to_dialog_id, forwarded_message);
if (forward_info != nullptr && !forward_info->is_imported && !is_forward_info_sender_hidden(forward_info.get()) && if (forward_info != nullptr && !forward_info->is_imported && !is_forward_info_sender_hidden(forward_info.get()) &&
!forward_info->message_id.is_valid() && !forward_info->sender_dialog_id.is_valid() && !forward_info->message_id.is_valid() && !forward_info->sender_dialog_id.is_valid() &&
forward_info->sender_user_id.is_valid()) { forward_info->sender_user_id.is_valid()) {
@ -28162,7 +28201,8 @@ Result<td_api::object_ptr<td_api::messages>> MessagesManager::forward_messages(
&need_update_dialog_pos, j + 1 != forwarded_message_contents.size(), &need_update_dialog_pos, j + 1 != forwarded_message_contents.size(),
std::move(forward_info)); std::move(forward_info));
} }
fix_forwarded_message(m, to_dialog_id, forwarded_message, forwarded_message_contents[j].media_album_id); fix_forwarded_message(m, to_dialog_id, forwarded_message, forwarded_message_contents[j].media_album_id,
drop_author);
m->in_game_share = in_game_share; m->in_game_share = in_game_share;
m->real_forward_from_dialog_id = from_dialog_id; m->real_forward_from_dialog_id = from_dialog_id;
m->real_forward_from_message_id = message_id; m->real_forward_from_message_id = message_id;
@ -28178,7 +28218,8 @@ Result<td_api::object_ptr<td_api::messages>> MessagesManager::forward_messages(
if (!forwarded_messages.empty()) { if (!forwarded_messages.empty()) {
CHECK(!only_preview); CHECK(!only_preview);
do_forward_messages(to_dialog_id, from_dialog_id, forwarded_messages, forwarded_message_ids, 0); do_forward_messages(to_dialog_id, from_dialog_id, forwarded_messages, forwarded_message_ids, drop_author,
drop_media_captions, 0);
} }
for (auto &copied_message : copied_messages) { for (auto &copied_message : copied_messages) {
@ -28837,7 +28878,7 @@ void MessagesManager::send_update_new_message(const Dialog *d, const Message *m)
MessagesManager::NotificationGroupInfo &MessagesManager::get_notification_group_info(Dialog *d, const Message *m) { MessagesManager::NotificationGroupInfo &MessagesManager::get_notification_group_info(Dialog *d, const Message *m) {
CHECK(d != nullptr); CHECK(d != nullptr);
CHECK(m != nullptr); CHECK(m != nullptr);
return is_from_mention_notification_group(d, m) ? d->mention_notification_group : d->message_notification_group; return is_from_mention_notification_group(m) ? d->mention_notification_group : d->message_notification_group;
} }
NotificationGroupId MessagesManager::get_dialog_notification_group_id(DialogId dialog_id, NotificationGroupId MessagesManager::get_dialog_notification_group_id(DialogId dialog_id,
@ -29107,13 +29148,13 @@ MessagesManager::MessageNotificationGroup MessagesManager::get_message_notificat
return result; return result;
} }
bool MessagesManager::is_from_mention_notification_group(const Dialog *d, const Message *m) { bool MessagesManager::is_from_mention_notification_group(const Message *m) {
return m->contains_mention && !m->is_mention_notification_disabled; return m->contains_mention && !m->is_mention_notification_disabled;
} }
bool MessagesManager::is_message_notification_active(const Dialog *d, const Message *m) { bool MessagesManager::is_message_notification_active(const Dialog *d, const Message *m) {
CHECK(!m->message_id.is_scheduled()); CHECK(!m->message_id.is_scheduled());
if (is_from_mention_notification_group(d, m)) { if (is_from_mention_notification_group(m)) {
return m->notification_id.get() > d->mention_notification_group.max_removed_notification_id.get() && return m->notification_id.get() > d->mention_notification_group.max_removed_notification_id.get() &&
m->message_id > d->mention_notification_group.max_removed_message_id && m->message_id > d->mention_notification_group.max_removed_message_id &&
(m->contains_unread_mention || m->message_id == d->pinned_message_notification_message_id); (m->contains_unread_mention || m->message_id == d->pinned_message_notification_message_id);
@ -29244,7 +29285,7 @@ vector<Notification> MessagesManager::get_message_notifications_from_database_fo
continue; continue;
} }
if (is_from_mention_notification_group(d, m) != from_mentions) { if (is_from_mention_notification_group(m) != from_mentions) {
VLOG(notifications) << "Receive from database " << m->message_id << " with " << m->notification_id VLOG(notifications) << "Receive from database " << m->message_id << " with " << m->notification_id
<< " from another group"; << " from another group";
continue; continue;
@ -29502,7 +29543,7 @@ void MessagesManager::on_get_message_notifications_from_database(DialogId dialog
continue; continue;
} }
if (is_from_mention_notification_group(d, m) != from_mentions) { if (is_from_mention_notification_group(m) != from_mentions) {
VLOG(notifications) << "Receive from database " << m->message_id << " with " << m->notification_id VLOG(notifications) << "Receive from database " << m->message_id << " with " << m->notification_id
<< " from another category"; << " from another category";
continue; continue;
@ -29569,7 +29610,7 @@ void MessagesManager::remove_message_notification(DialogId dialog_id, Notificati
CHECK(m != nullptr); CHECK(m != nullptr);
CHECK(m->notification_id == notification_id); CHECK(m->notification_id == notification_id);
CHECK(!m->message_id.is_scheduled()); CHECK(!m->message_id.is_scheduled());
if (is_from_mention_notification_group(d, m) == from_mentions && is_message_notification_active(d, m)) { if (is_from_mention_notification_group(m) == from_mentions && is_message_notification_active(d, m)) {
remove_message_notification_id(d, m, false, false); remove_message_notification_id(d, m, false, false);
} }
return; return;
@ -29632,8 +29673,8 @@ void MessagesManager::do_remove_message_notification(DialogId dialog_id, bool fr
CHECK(d != nullptr); CHECK(d != nullptr);
auto m = on_get_message_from_database(d, result[0], false, "do_remove_message_notification"); auto m = on_get_message_from_database(d, result[0], false, "do_remove_message_notification");
if (m != nullptr && m->notification_id == notification_id && if (m != nullptr && m->notification_id == notification_id && is_from_mention_notification_group(m) == from_mentions &&
is_from_mention_notification_group(d, m) == from_mentions && is_message_notification_active(d, m)) { is_message_notification_active(d, m)) {
remove_message_notification_id(d, m, false, false); remove_message_notification_id(d, m, false, false);
} }
} }
@ -29799,7 +29840,7 @@ bool MessagesManager::may_need_message_notification(const Dialog *d, const Messa
return false; return false;
} }
if (is_from_mention_notification_group(d, m)) { if (is_from_mention_notification_group(m)) {
return true; return true;
} }
@ -29830,7 +29871,7 @@ bool MessagesManager::add_new_message_notification(Dialog *d, Message *m, bool f
return false; return false;
} }
auto from_mentions = is_from_mention_notification_group(d, m); auto from_mentions = is_from_mention_notification_group(m);
bool is_pinned = m->content->get_type() == MessageContentType::PinMessage; bool is_pinned = m->content->get_type() == MessageContentType::PinMessage;
bool is_active = bool is_active =
from_mentions ? m->contains_unread_mention || is_pinned : m->message_id > d->last_read_inbox_message_id; from_mentions ? m->contains_unread_mention || is_pinned : m->message_id > d->last_read_inbox_message_id;
@ -29854,7 +29895,7 @@ bool MessagesManager::add_new_message_notification(Dialog *d, Message *m, bool f
DialogId settings_dialog_id = d->dialog_id; DialogId settings_dialog_id = d->dialog_id;
Dialog *settings_dialog = d; Dialog *settings_dialog = d;
if (is_from_mention_notification_group(d, m)) { if (is_from_mention_notification_group(m)) {
// have a mention, so use notification settings from the dialog with the sender // have a mention, so use notification settings from the dialog with the sender
auto sender_dialog_id = get_message_sender(m); auto sender_dialog_id = get_message_sender(m);
if (sender_dialog_id.is_valid()) { if (sender_dialog_id.is_valid()) {
@ -34345,7 +34386,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq
add_new_message_notification(d, message.get(), false); add_new_message_notification(d, message.get(), false);
} else { } else {
if (message->from_database && message->notification_id.is_valid() && if (message->from_database && message->notification_id.is_valid() &&
is_from_mention_notification_group(d, message.get()) && is_message_notification_active(d, message.get()) && is_from_mention_notification_group(message.get()) && is_message_notification_active(d, message.get()) &&
is_dialog_mention_notifications_disabled(d) && message_id != d->pinned_message_notification_message_id) { is_dialog_mention_notifications_disabled(d) && message_id != d->pinned_message_notification_message_id) {
auto notification_id = message->notification_id; auto notification_id = message->notification_id;
VLOG(notifications) << "Remove mention " << notification_id << " in " << message_id << " in " << dialog_id; VLOG(notifications) << "Remove mention " << notification_id << " in " << message_id << " in " << dialog_id;
@ -35039,7 +35080,7 @@ void MessagesManager::delete_message_from_database(Dialog *d, MessageId message_
if (m != nullptr && m->notification_id.is_valid()) { if (m != nullptr && m->notification_id.is_valid()) {
CHECK(!message_id.is_scheduled()); CHECK(!message_id.is_scheduled());
auto from_mentions = is_from_mention_notification_group(d, m); auto from_mentions = is_from_mention_notification_group(m);
auto &group_info = from_mentions ? d->mention_notification_group : d->message_notification_group; auto &group_info = from_mentions ? d->mention_notification_group : d->message_notification_group;
if (group_info.group_id.is_valid()) { if (group_info.group_id.is_valid()) {
@ -36014,6 +36055,9 @@ MessagesManager::Dialog *MessagesManager::add_new_dialog(unique_ptr<Dialog> &&d,
auto dialog_it = dialogs_.emplace(dialog_id, std::move(d)).first; auto dialog_it = dialogs_.emplace(dialog_id, std::move(d)).first;
CHECK(!being_added_new_dialog_id_.is_valid());
being_added_new_dialog_id_ = dialog_id;
loaded_dialogs_.erase(dialog_id); loaded_dialogs_.erase(dialog_id);
Dialog *dialog = dialog_it->second.get(); Dialog *dialog = dialog_it->second.get();
@ -36022,6 +36066,8 @@ MessagesManager::Dialog *MessagesManager::add_new_dialog(unique_ptr<Dialog> &&d,
send_update_new_chat(dialog); send_update_new_chat(dialog);
being_added_new_dialog_id_ = DialogId();
fix_new_dialog(dialog, std::move(last_database_message), last_database_message_id, order, last_clear_history_date, fix_new_dialog(dialog, std::move(last_database_message), last_database_message_id, order, last_clear_history_date,
last_clear_history_message_id, default_join_group_call_as_dialog_id, default_send_message_as_dialog_id, last_clear_history_message_id, default_join_group_call_as_dialog_id, default_send_message_as_dialog_id,
need_drop_default_send_message_as_dialog_id, is_loaded_from_database); need_drop_default_send_message_as_dialog_id, is_loaded_from_database);
@ -36155,6 +36201,7 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr<Message> &&last_datab
CHECK(counter_message.first > 0); CHECK(counter_message.first > 0);
counter_message.first--; counter_message.first--;
if (counter_message.first == 0) { if (counter_message.first == 0) {
LOG(INFO) << "Add postponed last database message in " << pending_dialog_id;
add_dialog_last_database_message(get_dialog(pending_dialog_id), std::move(counter_message.second)); add_dialog_last_database_message(get_dialog(pending_dialog_id), std::move(counter_message.second));
pending_add_dialog_last_database_message_.erase(pending_dialog_id); pending_add_dialog_last_database_message_.erase(pending_dialog_id);
} }
@ -38755,7 +38802,8 @@ void MessagesManager::on_binlog_events(vector<BinlogEvent> &&events) {
send_update_chat_last_message(to_dialog, "on_reforward_message"); send_update_chat_last_message(to_dialog, "on_reforward_message");
} }
do_forward_messages(to_dialog_id, from_dialog_id, forwarded_messages, log_event.message_ids, event.id_); do_forward_messages(to_dialog_id, from_dialog_id, forwarded_messages, log_event.message_ids,
log_event.drop_author, log_event.drop_media_captions, event.id_);
break; break;
} }
case LogEvent::HandlerType::DeleteMessage: { case LogEvent::HandlerType::DeleteMessage: {

View File

@ -1934,7 +1934,8 @@ class MessagesManager final : public Actor {
bool update_message_is_pinned(Dialog *d, Message *m, bool is_pin, const char *source); bool update_message_is_pinned(Dialog *d, Message *m, bool is_pin, const char *source);
void do_forward_messages(DialogId to_dialog_id, DialogId from_dialog_id, const vector<Message *> &messages, void do_forward_messages(DialogId to_dialog_id, DialogId from_dialog_id, const vector<Message *> &messages,
const vector<MessageId> &message_ids, uint64 log_event_id); const vector<MessageId> &message_ids, bool drop_author, bool drop_media_captions,
uint64 log_event_id);
Result<td_api::object_ptr<td_api::message>> forward_message(DialogId to_dialog_id, DialogId from_dialog_id, Result<td_api::object_ptr<td_api::message>> forward_message(DialogId to_dialog_id, DialogId from_dialog_id,
MessageId message_id, MessageId message_id,
@ -1945,8 +1946,8 @@ class MessagesManager final : public Actor {
unique_ptr<MessageForwardInfo> create_message_forward_info(DialogId from_dialog_id, DialogId to_dialog_id, unique_ptr<MessageForwardInfo> create_message_forward_info(DialogId from_dialog_id, DialogId to_dialog_id,
const Message *forwarded_message) const; const Message *forwarded_message) const;
void fix_forwarded_message(Message *m, DialogId to_dialog_id, const Message *forwarded_message, void fix_forwarded_message(Message *m, DialogId to_dialog_id, const Message *forwarded_message, int64 media_album_id,
int64 media_album_id) const; bool drop_author) const;
struct ForwardedMessages { struct ForwardedMessages {
struct CopiedMessage { struct CopiedMessage {
@ -1966,6 +1967,8 @@ class MessagesManager final : public Actor {
size_t index; size_t index;
}; };
vector<ForwardedMessageContent> forwarded_message_contents; vector<ForwardedMessageContent> forwarded_message_contents;
bool drop_author = false;
bool drop_media_captions = false;
Dialog *from_dialog; Dialog *from_dialog;
Dialog *to_dialog; Dialog *to_dialog;
@ -2368,7 +2371,7 @@ class MessagesManager final : public Actor {
void send_update_new_message(const Dialog *d, const Message *m); void send_update_new_message(const Dialog *d, const Message *m);
static bool is_from_mention_notification_group(const Dialog *d, const Message *m); static bool is_from_mention_notification_group(const Message *m);
static bool is_message_notification_active(const Dialog *d, const Message *m); static bool is_message_notification_active(const Dialog *d, const Message *m);
@ -3251,8 +3254,8 @@ class MessagesManager final : public Actor {
static uint64 save_reget_dialog_log_event(DialogId dialog_id); static uint64 save_reget_dialog_log_event(DialogId dialog_id);
static uint64 save_forward_messages_log_event(DialogId to_dialog_id, DialogId from_dialog_id, static uint64 save_forward_messages_log_event(DialogId to_dialog_id, DialogId from_dialog_id,
const vector<Message *> &messages, const vector<Message *> &messages, const vector<MessageId> &message_ids,
const vector<MessageId> &message_ids); bool drop_author, bool drop_media_captions);
static uint64 save_unpin_all_dialog_messages_on_server_log_event(DialogId dialog_id); static uint64 save_unpin_all_dialog_messages_on_server_log_event(DialogId dialog_id);
@ -3678,6 +3681,7 @@ class MessagesManager final : public Actor {
DialogId being_added_dialog_id_; DialogId being_added_dialog_id_;
DialogId being_added_by_new_message_dialog_id_; DialogId being_added_by_new_message_dialog_id_;
DialogId being_added_new_dialog_id_;
DialogId debug_channel_difference_dialog_; DialogId debug_channel_difference_dialog_;

View File

@ -1472,10 +1472,6 @@ void NotificationSettingsManager::after_get_difference() {
if (!channels_notification_settings_.is_synchronized) { if (!channels_notification_settings_.is_synchronized) {
send_get_scope_notification_settings_query(NotificationSettingsScope::Channel, Promise<>()); send_get_scope_notification_settings_query(NotificationSettingsScope::Channel, Promise<>());
} }
if (td_->is_online() && !are_saved_ringtones_reloaded_) {
reload_saved_ringtones(Auto());
}
} }
void NotificationSettingsManager::on_binlog_events(vector<BinlogEvent> &&events) { void NotificationSettingsManager::on_binlog_events(vector<BinlogEvent> &&events) {

View File

@ -35,6 +35,7 @@
#include "td/utils/Status.h" #include "td/utils/Status.h"
#include <cmath> #include <cmath>
#include <functional>
#include <limits> #include <limits>
namespace td { namespace td {
@ -418,14 +419,14 @@ void OptionManager::set_option(const string &name, td_api::object_ptr<td_api::Op
if (name != option_name) { if (name != option_name) {
return false; return false;
} }
if (value_constructor_id != td_api::optionValueInteger::ID &&
value_constructor_id != td_api::optionValueEmpty::ID) {
promise.set_error(Status::Error(400, PSLICE() << "Option \"" << name << "\" must have integer value"));
return false;
}
if (value_constructor_id == td_api::optionValueEmpty::ID) { if (value_constructor_id == td_api::optionValueEmpty::ID) {
G()->shared_config().set_option_empty(option_name); G()->shared_config().set_option_empty(option_name);
} else { } else {
if (value_constructor_id != td_api::optionValueInteger::ID) {
promise.set_error(Status::Error(400, PSLICE() << "Option \"" << name << "\" must have integer value"));
return false;
}
int64 int_value = static_cast<td_api::optionValueInteger *>(value.get())->value_; int64 int_value = static_cast<td_api::optionValueInteger *>(value.get())->value_;
if (int_value < min_value || int_value > max_value) { if (int_value < min_value || int_value > max_value) {
promise.set_error(Status::Error(400, PSLICE() << "Option's \"" << name << "\" value " << int_value promise.set_error(Status::Error(400, PSLICE() << "Option's \"" << name << "\" value " << int_value
@ -443,14 +444,14 @@ void OptionManager::set_option(const string &name, td_api::object_ptr<td_api::Op
if (name != option_name) { if (name != option_name) {
return false; return false;
} }
if (value_constructor_id != td_api::optionValueBoolean::ID &&
value_constructor_id != td_api::optionValueEmpty::ID) {
promise.set_error(Status::Error(400, PSLICE() << "Option \"" << name << "\" must have boolean value"));
return false;
}
if (value_constructor_id == td_api::optionValueEmpty::ID) { if (value_constructor_id == td_api::optionValueEmpty::ID) {
G()->shared_config().set_option_empty(name); G()->shared_config().set_option_empty(name);
} else { } else {
if (value_constructor_id != td_api::optionValueBoolean::ID) {
promise.set_error(Status::Error(400, PSLICE() << "Option \"" << name << "\" must have boolean value"));
return false;
}
bool bool_value = static_cast<td_api::optionValueBoolean *>(value.get())->value_; bool bool_value = static_cast<td_api::optionValueBoolean *>(value.get())->value_;
G()->shared_config().set_option_boolean(name, bool_value); G()->shared_config().set_option_boolean(name, bool_value);
} }
@ -458,17 +459,18 @@ void OptionManager::set_option(const string &name, td_api::object_ptr<td_api::Op
return true; return true;
}; };
auto set_string_option = [&](Slice option_name, auto check_value) { auto set_string_option = [&](Slice option_name, std::function<bool(Slice)> check_value) {
if (name != option_name) { if (name != option_name) {
return false; return false;
} }
if (value_constructor_id != td_api::optionValueString::ID && value_constructor_id != td_api::optionValueEmpty::ID) {
promise.set_error(Status::Error(400, PSLICE() << "Option \"" << name << "\" must have string value"));
return false;
}
if (value_constructor_id == td_api::optionValueEmpty::ID) { if (value_constructor_id == td_api::optionValueEmpty::ID) {
G()->shared_config().set_option_empty(name); G()->shared_config().set_option_empty(name);
} else { } else {
if (value_constructor_id != td_api::optionValueString::ID) {
promise.set_error(Status::Error(400, PSLICE() << "Option \"" << name << "\" must have string value"));
return false;
}
const string &str_value = static_cast<td_api::optionValueString *>(value.get())->value_; const string &str_value = static_cast<td_api::optionValueString *>(value.get())->value_;
if (str_value.empty()) { if (str_value.empty()) {
G()->shared_config().set_option_empty(name); G()->shared_config().set_option_empty(name);
@ -651,10 +653,10 @@ void OptionManager::set_option(const string &name, td_api::object_ptr<td_api::Op
} }
bool is_online = value_constructor_id == td_api::optionValueEmpty::ID || bool is_online = value_constructor_id == td_api::optionValueEmpty::ID ||
static_cast<const td_api::optionValueBoolean *>(value.get())->value_; static_cast<const td_api::optionValueBoolean *>(value.get())->value_;
td_->set_is_online(is_online);
if (!is_bot) { if (!is_bot) {
send_closure(td_->state_manager_, &StateManager::on_online, is_online); send_closure(td_->state_manager_, &StateManager::on_online, is_online);
} }
td_->set_is_online(is_online);
return promise.set_value(Unit()); return promise.set_value(Unit());
} }
break; break;

View File

@ -166,7 +166,7 @@ void PhoneNumberManager::process_check_code_result(Result<tl_object_ptr<telegram
return on_query_error(result.move_as_error()); return on_query_error(result.move_as_error());
} }
send_closure(G()->contacts_manager(), &ContactsManager::on_get_user, result.move_as_ok(), "process_check_code_result", send_closure(G()->contacts_manager(), &ContactsManager::on_get_user, result.move_as_ok(), "process_check_code_result",
true, false); true);
state_ = State::Ok; state_ = State::Ok;
on_query_ok(); on_query_ok();
} }

View File

@ -239,6 +239,9 @@ PollManager::PollManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::m
close_poll_timeout_.set_callback(on_close_poll_timeout_callback); close_poll_timeout_.set_callback(on_close_poll_timeout_callback);
close_poll_timeout_.set_callback_data(static_cast<void *>(this)); close_poll_timeout_.set_callback_data(static_cast<void *>(this));
unload_poll_timeout_.set_callback(on_unload_poll_timeout_callback);
unload_poll_timeout_.set_callback_data(static_cast<void *>(this));
} }
void PollManager::start_up() { void PollManager::start_up() {
@ -283,6 +286,15 @@ void PollManager::on_close_poll_timeout_callback(void *poll_manager_ptr, int64 p
send_closure_later(poll_manager->actor_id(poll_manager), &PollManager::on_close_poll_timeout, PollId(poll_id_int)); send_closure_later(poll_manager->actor_id(poll_manager), &PollManager::on_close_poll_timeout, PollId(poll_id_int));
} }
void PollManager::on_unload_poll_timeout_callback(void *poll_manager_ptr, int64 poll_id_int) {
if (G()->close_flag()) {
return;
}
auto poll_manager = static_cast<PollManager *>(poll_manager_ptr);
send_closure_later(poll_manager->actor_id(poll_manager), &PollManager::on_unload_poll_timeout, PollId(poll_id_int));
}
bool PollManager::is_local_poll_id(PollId poll_id) { bool PollManager::is_local_poll_id(PollId poll_id) {
return poll_id.get() < 0 && poll_id.get() > std::numeric_limits<int32>::min(); return poll_id.get() < 0 && poll_id.get() > std::numeric_limits<int32>::min();
} }
@ -296,11 +308,22 @@ const PollManager::Poll *PollManager::get_poll(PollId poll_id) const {
} }
} }
const PollManager::Poll *PollManager::get_poll(PollId poll_id) {
auto p = polls_.find(poll_id);
if (p == polls_.end()) {
return nullptr;
} else {
schedule_poll_unload(poll_id);
return p->second.get();
}
}
PollManager::Poll *PollManager::get_poll_editable(PollId poll_id) { PollManager::Poll *PollManager::get_poll_editable(PollId poll_id) {
auto p = polls_.find(poll_id); auto p = polls_.find(poll_id);
if (p == polls_.end()) { if (p == polls_.end()) {
return nullptr; return nullptr;
} else { } else {
schedule_poll_unload(poll_id);
return p->second.get(); return p->second.get();
} }
} }
@ -310,13 +333,18 @@ bool PollManager::have_poll(PollId poll_id) const {
} }
void PollManager::notify_on_poll_update(PollId poll_id) { void PollManager::notify_on_poll_update(PollId poll_id) {
auto it = poll_messages_.find(poll_id); auto server_it = server_poll_messages_.find(poll_id);
if (it == poll_messages_.end()) { if (server_it != server_poll_messages_.end()) {
return; for (const auto &full_message_id : server_it->second) {
td_->messages_manager_->on_external_update_message_content(full_message_id);
}
} }
for (const auto &full_message_id : it->second) { auto other_it = other_poll_messages_.find(poll_id);
td_->messages_manager_->on_external_update_message_content(full_message_id); if (other_it != other_poll_messages_.end()) {
for (const auto &full_message_id : other_it->second) {
td_->messages_manager_->on_external_update_message_content(full_message_id);
}
} }
} }
@ -623,38 +651,71 @@ PollId PollManager::create_poll(string &&question, vector<string> &&options, boo
void PollManager::register_poll(PollId poll_id, FullMessageId full_message_id, const char *source) { void PollManager::register_poll(PollId poll_id, FullMessageId full_message_id, const char *source) {
CHECK(have_poll(poll_id)); CHECK(have_poll(poll_id));
if (full_message_id.get_message_id().is_scheduled()) { if (full_message_id.get_message_id().is_scheduled() || !full_message_id.get_message_id().is_server()) {
return; bool is_inserted = other_poll_messages_[poll_id].insert(full_message_id).second;
} LOG_CHECK(is_inserted) << source << ' ' << poll_id << ' ' << full_message_id;
if (!full_message_id.get_message_id().is_server()) { unload_poll_timeout_.cancel_timeout(poll_id.get());
return; return;
} }
LOG(INFO) << "Register " << poll_id << " from " << full_message_id << " from " << source; LOG(INFO) << "Register " << poll_id << " from " << full_message_id << " from " << source;
bool is_inserted = poll_messages_[poll_id].insert(full_message_id).second; bool is_inserted = server_poll_messages_[poll_id].insert(full_message_id).second;
LOG_CHECK(is_inserted) << source << " " << poll_id << " " << full_message_id; LOG_CHECK(is_inserted) << source << ' ' << poll_id << ' ' << full_message_id;
auto poll = get_poll(poll_id); auto poll = get_poll(poll_id);
CHECK(poll != nullptr); CHECK(poll != nullptr);
if (!td_->auth_manager_->is_bot() && !is_local_poll_id(poll_id) && if (!td_->auth_manager_->is_bot() && !is_local_poll_id(poll_id) &&
!(poll->is_closed && poll->is_updated_after_close)) { !(poll->is_closed && poll->is_updated_after_close)) {
update_poll_timeout_.add_timeout_in(poll_id.get(), 0); update_poll_timeout_.add_timeout_in(poll_id.get(), 0);
} }
unload_poll_timeout_.cancel_timeout(poll_id.get());
} }
void PollManager::unregister_poll(PollId poll_id, FullMessageId full_message_id, const char *source) { void PollManager::unregister_poll(PollId poll_id, FullMessageId full_message_id, const char *source) {
CHECK(have_poll(poll_id)); CHECK(have_poll(poll_id));
if (full_message_id.get_message_id().is_scheduled()) { if (full_message_id.get_message_id().is_scheduled() || !full_message_id.get_message_id().is_server()) {
return; auto &message_ids = other_poll_messages_[poll_id];
} auto is_deleted = message_ids.erase(full_message_id) > 0;
if (!full_message_id.get_message_id().is_server()) { LOG_CHECK(is_deleted) << source << ' ' << poll_id << ' ' << full_message_id;
if (message_ids.empty()) {
other_poll_messages_.erase(poll_id);
schedule_poll_unload(poll_id);
}
return; return;
} }
LOG(INFO) << "Unregister " << poll_id << " from " << full_message_id << " from " << source; LOG(INFO) << "Unregister " << poll_id << " from " << full_message_id << " from " << source;
auto &message_ids = poll_messages_[poll_id]; auto &message_ids = server_poll_messages_[poll_id];
auto is_deleted = message_ids.erase(full_message_id) > 0; auto is_deleted = message_ids.erase(full_message_id) > 0;
LOG_CHECK(is_deleted) << source << " " << poll_id << " " << full_message_id; LOG_CHECK(is_deleted) << source << ' ' << poll_id << ' ' << full_message_id;
if (message_ids.empty()) { if (message_ids.empty()) {
poll_messages_.erase(poll_id); server_poll_messages_.erase(poll_id);
update_poll_timeout_.cancel_timeout(poll_id.get()); update_poll_timeout_.cancel_timeout(poll_id.get());
schedule_poll_unload(poll_id);
}
}
bool PollManager::can_unload_poll(PollId poll_id) {
if (is_local_poll_id(poll_id) || server_poll_messages_.count(poll_id) != 0 ||
other_poll_messages_.count(poll_id) != 0 || pending_answers_.count(poll_id) != 0 ||
being_closed_polls_.count(poll_id) != 0) {
return false;
}
auto it = poll_voters_.find(poll_id);
if (it != poll_voters_.end() && !it->second.empty()) {
for (auto &voters : it->second) {
if (!voters.pending_queries.empty()) {
return false;
}
}
}
return true;
}
void PollManager::schedule_poll_unload(PollId poll_id) {
if (can_unload_poll(poll_id)) {
unload_poll_timeout_.set_timeout_in(poll_id.get(), UNLOAD_POLL_DELAY);
} }
} }
@ -764,6 +825,7 @@ void PollManager::do_set_poll_answer(PollId poll_id, FullMessageId full_message_
binlog_erase(G()->td_db()->get_binlog(), log_event_id); binlog_erase(G()->td_db()->get_binlog(), log_event_id);
return; return;
} }
unload_poll_timeout_.cancel_timeout(poll_id.get());
auto &pending_answer = pending_answers_[poll_id]; auto &pending_answer = pending_answers_[poll_id];
if (!pending_answer.promises_.empty() && pending_answer.options_ == options) { if (!pending_answer.promises_.empty() && pending_answer.options_ == options) {
@ -987,6 +1049,8 @@ void PollManager::get_poll_voters(PollId poll_id, FullMessageId full_message_id,
return; return;
} }
unload_poll_timeout_.cancel_timeout(poll_id.get());
auto query_promise = auto query_promise =
PromiseCreator::lambda([actor_id = actor_id(this), poll_id, option_id, offset = voters.next_offset, PromiseCreator::lambda([actor_id = actor_id(this), poll_id, option_id, offset = voters.next_offset,
limit](Result<tl_object_ptr<telegram_api::messages_votesList>> &&result) mutable { limit](Result<tl_object_ptr<telegram_api::messages_votesList>> &&result) mutable {
@ -1136,6 +1200,8 @@ void PollManager::do_stop_poll(PollId poll_id, FullMessageId full_message_id, un
binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::StopPoll, get_log_event_storer(log_event)); binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::StopPoll, get_log_event_storer(log_event));
} }
unload_poll_timeout_.cancel_timeout(poll_id.get());
bool is_inserted = being_closed_polls_.insert(poll_id).second; bool is_inserted = being_closed_polls_.insert(poll_id).second;
CHECK(is_inserted); CHECK(is_inserted);
auto new_promise = get_erase_log_event_promise(log_event_id, std::move(promise)); auto new_promise = get_erase_log_event_promise(log_event_id, std::move(promise));
@ -1168,8 +1234,7 @@ void PollManager::on_update_poll_timeout(PollId poll_id) {
CHECK(!is_local_poll_id(poll_id)); CHECK(!is_local_poll_id(poll_id));
auto poll = get_poll(poll_id); auto poll = get_poll(poll_id);
CHECK(poll != nullptr); if (poll == nullptr || (poll->is_closed && poll->is_updated_after_close)) {
if (poll->is_closed && poll->is_updated_after_close) {
return; return;
} }
if (pending_answers_.count(poll_id) > 0) { if (pending_answers_.count(poll_id) > 0) {
@ -1177,8 +1242,8 @@ void PollManager::on_update_poll_timeout(PollId poll_id) {
return; return;
} }
auto it = poll_messages_.find(poll_id); auto it = server_poll_messages_.find(poll_id);
if (it == poll_messages_.end()) { if (it == server_poll_messages_.end()) {
return; return;
} }
@ -1198,8 +1263,7 @@ void PollManager::on_close_poll_timeout(PollId poll_id) {
CHECK(!is_local_poll_id(poll_id)); CHECK(!is_local_poll_id(poll_id));
auto poll = get_poll_editable(poll_id); auto poll = get_poll_editable(poll_id);
CHECK(poll != nullptr); if (poll == nullptr || poll->is_closed || poll->close_date == 0) {
if (poll->is_closed || poll->close_date == 0) {
return; return;
} }
@ -1219,10 +1283,34 @@ void PollManager::on_close_poll_timeout(PollId poll_id) {
} }
} }
void PollManager::on_unload_poll_timeout(PollId poll_id) {
if (G()->close_flag()) {
return;
}
CHECK(!is_local_poll_id(poll_id));
if (!can_unload_poll(poll_id)) {
return;
}
LOG(INFO) << "Unload " << poll_id;
update_poll_timeout_.cancel_timeout(poll_id.get());
close_poll_timeout_.cancel_timeout(poll_id.get());
auto is_deleted = polls_.erase(poll_id) > 0;
CHECK(is_deleted);
poll_voters_.erase(poll_id);
loaded_from_database_polls_.erase(poll_id);
}
void PollManager::on_get_poll_results(PollId poll_id, uint64 generation, void PollManager::on_get_poll_results(PollId poll_id, uint64 generation,
Result<tl_object_ptr<telegram_api::Updates>> result) { Result<tl_object_ptr<telegram_api::Updates>> result) {
auto poll = get_poll(poll_id); auto poll = get_poll(poll_id);
CHECK(poll != nullptr); if (poll == nullptr) {
return;
}
if (result.is_error()) { if (result.is_error()) {
if (!(poll->is_closed && poll->is_updated_after_close) && !G()->close_flag() && !td_->auth_manager_->is_bot()) { if (!(poll->is_closed && poll->is_updated_after_close) && !G()->close_flag() && !td_->auth_manager_->is_bot()) {
auto timeout = get_polling_timeout(); auto timeout = get_polling_timeout();
@ -1250,7 +1338,7 @@ void PollManager::on_online() {
return; return;
} }
for (auto &it : poll_messages_) { for (auto &it : server_poll_messages_) {
auto poll_id = it.first; auto poll_id = it.first;
if (update_poll_timeout_.has_timeout(poll_id.get())) { if (update_poll_timeout_.has_timeout(poll_id.get())) {
auto timeout = Random::fast(3, 30); auto timeout = Random::fast(3, 30);
@ -1643,6 +1731,8 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptr<telegram_api::poll
} }
if (need_update_poll && (is_changed || (poll->is_closed && being_closed_polls_.erase(poll_id) != 0))) { if (need_update_poll && (is_changed || (poll->is_closed && being_closed_polls_.erase(poll_id) != 0))) {
send_closure(G()->td(), &Td::send_update, td_api::make_object<td_api::updatePoll>(get_poll_object(poll_id, poll))); send_closure(G()->td(), &Td::send_update, td_api::make_object<td_api::updatePoll>(get_poll_object(poll_id, poll)));
schedule_poll_unload(poll_id);
} }
return poll_id; return poll_id;
} }

View File

@ -138,6 +138,7 @@ class PollManager final : public Actor {
}; };
static constexpr int32 MAX_GET_POLL_VOTERS = 50; // server side limit static constexpr int32 MAX_GET_POLL_VOTERS = 50; // server side limit
static constexpr int32 UNLOAD_POLL_DELAY = 600; // some reasonable value
class SetPollAnswerLogEvent; class SetPollAnswerLogEvent;
class StopPollLogEvent; class StopPollLogEvent;
@ -149,6 +150,8 @@ class PollManager final : public Actor {
static void on_close_poll_timeout_callback(void *poll_manager_ptr, int64 poll_id_int); static void on_close_poll_timeout_callback(void *poll_manager_ptr, int64 poll_id_int);
static void on_unload_poll_timeout_callback(void *poll_manager_ptr, int64 poll_id_int);
static td_api::object_ptr<td_api::pollOption> get_poll_option_object(const PollOption &poll_option); static td_api::object_ptr<td_api::pollOption> get_poll_option_object(const PollOption &poll_option);
static telegram_api::object_ptr<telegram_api::pollAnswer> get_input_poll_option(const PollOption &poll_option); static telegram_api::object_ptr<telegram_api::pollAnswer> get_input_poll_option(const PollOption &poll_option);
@ -161,8 +164,14 @@ class PollManager final : public Actor {
const Poll *get_poll(PollId poll_id) const; const Poll *get_poll(PollId poll_id) const;
const Poll *get_poll(PollId poll_id);
Poll *get_poll_editable(PollId poll_id); Poll *get_poll_editable(PollId poll_id);
bool can_unload_poll(PollId poll_id);
void schedule_poll_unload(PollId poll_id);
void notify_on_poll_update(PollId poll_id); void notify_on_poll_update(PollId poll_id);
static string get_poll_database_key(PollId poll_id); static string get_poll_database_key(PollId poll_id);
@ -177,6 +186,8 @@ class PollManager final : public Actor {
void on_close_poll_timeout(PollId poll_id); void on_close_poll_timeout(PollId poll_id);
void on_unload_poll_timeout(PollId poll_id);
void on_online(); void on_online();
Poll *get_poll_force(PollId poll_id); Poll *get_poll_force(PollId poll_id);
@ -206,12 +217,14 @@ class PollManager final : public Actor {
MultiTimeout update_poll_timeout_{"UpdatePollTimeout"}; MultiTimeout update_poll_timeout_{"UpdatePollTimeout"};
MultiTimeout close_poll_timeout_{"ClosePollTimeout"}; MultiTimeout close_poll_timeout_{"ClosePollTimeout"};
MultiTimeout unload_poll_timeout_{"UnloadPollTimeout"};
Td *td_; Td *td_;
ActorShared<> parent_; ActorShared<> parent_;
FlatHashMap<PollId, unique_ptr<Poll>, PollIdHash> polls_; FlatHashMap<PollId, unique_ptr<Poll>, PollIdHash> polls_;
FlatHashMap<PollId, FlatHashSet<FullMessageId, FullMessageIdHash>, PollIdHash> poll_messages_; FlatHashMap<PollId, FlatHashSet<FullMessageId, FullMessageIdHash>, PollIdHash> server_poll_messages_;
FlatHashMap<PollId, FlatHashSet<FullMessageId, FullMessageIdHash>, PollIdHash> other_poll_messages_;
struct PendingPollAnswer { struct PendingPollAnswer {
vector<string> options_; vector<string> options_;

View File

@ -0,0 +1,25 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
//
// 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/SecretInputMedia.h"
#include "td/telegram/files/FileManager.h"
namespace td {
SecretInputMedia::SecretInputMedia(tl_object_ptr<telegram_api::InputEncryptedFile> input_file, BufferSlice &&thumbnail,
Dimensions thumbnail_dimensions, const string &mime_type, const FileView &file_view,
vector<tl_object_ptr<secret_api::DocumentAttribute>> &&attributes,
const string &caption)
: input_file_(std::move(input_file)) {
auto &encryption_key = file_view.encryption_key();
decrypted_media_ = secret_api::make_object<secret_api::decryptedMessageMediaDocument>(
std::move(thumbnail), thumbnail_dimensions.width, thumbnail_dimensions.height, mime_type,
narrow_cast<int32>(file_view.size()), BufferSlice(encryption_key.key_slice()),
BufferSlice(encryption_key.iv_slice()), std::move(attributes), caption);
}
} // namespace td

View File

@ -6,11 +6,17 @@
// //
#pragma once #pragma once
#include "td/telegram/PhotoSize.h"
#include "td/telegram/secret_api.h" #include "td/telegram/secret_api.h"
#include "td/telegram/telegram_api.h" #include "td/telegram/telegram_api.h"
#include "td/utils/buffer.h"
#include "td/utils/common.h"
namespace td { namespace td {
class FileView;
struct SecretInputMedia { struct SecretInputMedia {
tl_object_ptr<telegram_api::InputEncryptedFile> input_file_; tl_object_ptr<telegram_api::InputEncryptedFile> input_file_;
tl_object_ptr<secret_api::DecryptedMessageMedia> decrypted_media_; tl_object_ptr<secret_api::DecryptedMessageMedia> decrypted_media_;
@ -22,6 +28,10 @@ struct SecretInputMedia {
: input_file_(std::move(input_file)), decrypted_media_(std::move(decrypted_media)) { : input_file_(std::move(input_file)), decrypted_media_(std::move(decrypted_media)) {
} }
SecretInputMedia(tl_object_ptr<telegram_api::InputEncryptedFile> input_file, BufferSlice &&thumbnail,
Dimensions thumbnail_dimensions, const string &mime_type, const FileView &file_view,
vector<tl_object_ptr<secret_api::DocumentAttribute>> &&attributes, const string &caption);
bool empty() const { bool empty() const {
return decrypted_media_ == nullptr; return decrypted_media_ == nullptr;
} }

View File

@ -1462,6 +1462,10 @@ void StickersManager::reload_special_sticker_set_by_type(SpecialStickerSetType t
if (G()->close_flag()) { if (G()->close_flag()) {
return; return;
} }
if (disable_animated_emojis_ &&
(type == SpecialStickerSetType::animated_emoji() || type == SpecialStickerSetType::animated_emoji_click())) {
return;
}
auto &sticker_set = add_special_sticker_set(type); auto &sticker_set = add_special_sticker_set(type);
if (sticker_set.is_being_reloaded_) { if (sticker_set.is_being_reloaded_) {
@ -1534,8 +1538,9 @@ void StickersManager::on_load_special_sticker_set(const SpecialStickerSetType &t
auto pending_get_requests = std::move(pending_get_animated_emoji_click_stickers_); auto pending_get_requests = std::move(pending_get_animated_emoji_click_stickers_);
reset_to_empty(pending_get_animated_emoji_click_stickers_); reset_to_empty(pending_get_animated_emoji_click_stickers_);
for (auto &pending_request : pending_get_requests) { for (auto &pending_request : pending_get_requests) {
choose_animated_emoji_click_sticker(sticker_set, pending_request.message_text_, pending_request.full_message_id_, choose_animated_emoji_click_sticker(sticker_set, std::move(pending_request.message_text_),
pending_request.start_time_, std::move(pending_request.promise_)); pending_request.full_message_id_, pending_request.start_time_,
std::move(pending_request.promise_));
} }
auto pending_click_requests = std::move(pending_on_animated_emoji_message_clicked_); auto pending_click_requests = std::move(pending_on_animated_emoji_message_clicked_);
reset_to_empty(pending_on_animated_emoji_message_clicked_); reset_to_empty(pending_on_animated_emoji_message_clicked_);
@ -2079,7 +2084,7 @@ std::pair<FileId, int> StickersManager::get_animated_emoji_sticker(const Sticker
return {}; return {};
} }
auto emoji_without_modifiers = remove_emoji_modifiers(emoji).str(); auto emoji_without_modifiers = remove_emoji_modifiers(emoji);
auto it = sticker_set->emoji_stickers_map_.find(emoji_without_modifiers); auto it = sticker_set->emoji_stickers_map_.find(emoji_without_modifiers);
if (it == sticker_set->emoji_stickers_map_.end()) { if (it == sticker_set->emoji_stickers_map_.end()) {
return {}; return {};
@ -2748,13 +2753,13 @@ SecretInputMedia StickersManager::get_secret_input_media(FileId sticker_file_id,
} }
if (file_view.is_encrypted_secret()) { if (file_view.is_encrypted_secret()) {
auto &encryption_key = file_view.encryption_key(); return {std::move(input_file),
return SecretInputMedia{std::move(input_file), std::move(thumbnail),
make_tl_object<secret_api::decryptedMessageMediaDocument>( sticker->s_thumbnail.dimensions,
std::move(thumbnail), sticker->s_thumbnail.dimensions.width, get_sticker_format_mime_type(sticker->format),
sticker->s_thumbnail.dimensions.height, get_sticker_format_mime_type(sticker->format), file_view,
narrow_cast<int32>(file_view.size()), BufferSlice(encryption_key.key_slice()), std::move(attributes),
BufferSlice(encryption_key.iv_slice()), std::move(attributes), "")}; string()};
} else { } else {
CHECK(!file_view.is_encrypted()); CHECK(!file_view.is_encrypted());
auto &remote_location = file_view.remote_location(); auto &remote_location = file_view.remote_location();
@ -3084,7 +3089,7 @@ StickerSetId StickersManager::on_get_messages_sticker_set(StickerSetId sticker_s
s->emoji_stickers_map_.clear(); s->emoji_stickers_map_.clear();
s->sticker_emojis_map_.clear(); s->sticker_emojis_map_.clear();
for (auto &pack : packs) { for (auto &pack : packs) {
auto cleaned_emoji = remove_emoji_modifiers(pack->emoticon_).str(); auto cleaned_emoji = remove_emoji_modifiers(pack->emoticon_);
if (cleaned_emoji.empty()) { if (cleaned_emoji.empty()) {
LOG(ERROR) << "Receive empty emoji in " << set_id << "/" << s->short_name << " from " << source; LOG(ERROR) << "Receive empty emoji in " << set_id << "/" << s->short_name << " from " << source;
continue; continue;
@ -4640,11 +4645,11 @@ vector<FileId> StickersManager::get_animated_emoji_click_stickers(const StickerS
return result; return result;
} }
void StickersManager::choose_animated_emoji_click_sticker(const StickerSet *sticker_set, Slice message_text, void StickersManager::choose_animated_emoji_click_sticker(const StickerSet *sticker_set, string message_text,
FullMessageId full_message_id, double start_time, FullMessageId full_message_id, double start_time,
Promise<td_api::object_ptr<td_api::sticker>> &&promise) { Promise<td_api::object_ptr<td_api::sticker>> &&promise) {
CHECK(sticker_set->was_loaded); CHECK(sticker_set->was_loaded);
message_text = remove_emoji_modifiers(message_text); remove_emoji_modifiers_in_place(message_text);
if (message_text.empty()) { if (message_text.empty()) {
return promise.set_error(Status::Error(400, "Message is not an animated emoji message")); return promise.set_error(Status::Error(400, "Message is not an animated emoji message"));
} }
@ -4682,7 +4687,7 @@ void StickersManager::choose_animated_emoji_click_sticker(const StickerSet *stic
} }
if (last_clicked_animated_emoji_ != message_text) { if (last_clicked_animated_emoji_ != message_text) {
pending_animated_emoji_clicks_.clear(); pending_animated_emoji_clicks_.clear();
last_clicked_animated_emoji_ = message_text.str(); last_clicked_animated_emoji_ = std::move(message_text);
} }
if (!pending_animated_emoji_clicks_.empty() && found_stickers.size() >= 2) { if (!pending_animated_emoji_clicks_.empty() && found_stickers.size() >= 2) {
@ -4798,7 +4803,7 @@ void StickersManager::flush_sent_animated_emoji_clicks() {
sent_animated_emoji_clicks_.erase(sent_animated_emoji_clicks_.begin(), it); sent_animated_emoji_clicks_.erase(sent_animated_emoji_clicks_.begin(), it);
} }
bool StickersManager::is_sent_animated_emoji_click(DialogId dialog_id, Slice emoji) { bool StickersManager::is_sent_animated_emoji_click(DialogId dialog_id, const string &emoji) {
flush_sent_animated_emoji_clicks(); flush_sent_animated_emoji_clicks();
for (const auto &click : sent_animated_emoji_clicks_) { for (const auto &click : sent_animated_emoji_clicks_) {
if (click.dialog_id == dialog_id && click.emoji == emoji) { if (click.dialog_id == dialog_id && click.emoji == emoji) {
@ -4808,7 +4813,7 @@ bool StickersManager::is_sent_animated_emoji_click(DialogId dialog_id, Slice emo
return false; return false;
} }
Status StickersManager::on_animated_emoji_message_clicked(Slice emoji, FullMessageId full_message_id, string data) { Status StickersManager::on_animated_emoji_message_clicked(string &&emoji, FullMessageId full_message_id, string data) {
if (td_->auth_manager_->is_bot() || disable_animated_emojis_) { if (td_->auth_manager_->is_bot() || disable_animated_emojis_) {
return Status::OK(); return Status::OK();
} }
@ -4871,7 +4876,7 @@ Status StickersManager::on_animated_emoji_message_clicked(Slice emoji, FullMessa
load_special_sticker_set(special_sticker_set); load_special_sticker_set(special_sticker_set);
PendingOnAnimatedEmojiClicked pending_request; PendingOnAnimatedEmojiClicked pending_request;
pending_request.emoji_ = emoji.str(); pending_request.emoji_ = std::move(emoji);
pending_request.full_message_id_ = full_message_id; pending_request.full_message_id_ = full_message_id;
pending_request.clicks_ = std::move(clicks); pending_request.clicks_ = std::move(clicks);
pending_on_animated_emoji_message_clicked_.push_back(std::move(pending_request)); pending_on_animated_emoji_message_clicked_.push_back(std::move(pending_request));
@ -7627,26 +7632,6 @@ td_api::object_ptr<td_api::httpUrl> StickersManager::get_emoji_suggestions_url_r
return result; return result;
} }
void StickersManager::after_get_difference() {
if (td_->auth_manager_->is_bot()) {
return;
}
reload_reactions();
if (td_->is_online()) {
get_installed_sticker_sets(false, Auto());
get_installed_sticker_sets(true, Auto());
get_featured_sticker_sets(0, 1000, Auto());
get_recent_stickers(false, Auto());
get_recent_stickers(true, Auto());
get_favorite_stickers(Auto());
if (!disable_animated_emojis_) {
reload_special_sticker_set_by_type(SpecialStickerSetType::animated_emoji());
reload_special_sticker_set_by_type(SpecialStickerSetType::animated_emoji_click());
}
}
}
void StickersManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const { void StickersManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const {
if (td_->auth_manager_->is_bot()) { if (td_->auth_manager_->is_bot()) {
return; return;

View File

@ -89,9 +89,9 @@ class StickersManager final : public Actor {
void on_send_animated_emoji_clicks(DialogId dialog_id, const string &emoji); void on_send_animated_emoji_clicks(DialogId dialog_id, const string &emoji);
bool is_sent_animated_emoji_click(DialogId dialog_id, Slice emoji); bool is_sent_animated_emoji_click(DialogId dialog_id, const string &emoji);
Status on_animated_emoji_message_clicked(Slice emoji, FullMessageId full_message_id, string data); Status on_animated_emoji_message_clicked(string &&emoji, FullMessageId full_message_id, string data);
bool is_active_reaction(const string &reaction) const; bool is_active_reaction(const string &reaction) const;
@ -135,6 +135,10 @@ class StickersManager final : public Actor {
void view_featured_sticker_sets(const vector<StickerSetId> &sticker_set_ids); void view_featured_sticker_sets(const vector<StickerSetId> &sticker_set_ids);
void reload_reactions();
void reload_special_sticker_set_by_type(SpecialStickerSetType type, bool is_recursive = false);
void on_get_available_reactions(tl_object_ptr<telegram_api::messages_AvailableReactions> &&available_reactions_ptr); void on_get_available_reactions(tl_object_ptr<telegram_api::messages_AvailableReactions> &&available_reactions_ptr);
void on_get_installed_sticker_sets(bool is_masks, tl_object_ptr<telegram_api::messages_AllStickers> &&stickers_ptr); void on_get_installed_sticker_sets(bool is_masks, tl_object_ptr<telegram_api::messages_AllStickers> &&stickers_ptr);
@ -321,8 +325,6 @@ class StickersManager final : public Actor {
void send_get_attached_stickers_query(FileId file_id, Promise<Unit> &&promise); void send_get_attached_stickers_query(FileId file_id, Promise<Unit> &&promise);
void after_get_difference();
void get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const; void get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const;
template <class StorerT> template <class StorerT>
@ -676,7 +678,7 @@ class StickersManager final : public Actor {
vector<FileId> get_animated_emoji_click_stickers(const StickerSet *sticker_set, Slice emoji) const; vector<FileId> get_animated_emoji_click_stickers(const StickerSet *sticker_set, Slice emoji) const;
void choose_animated_emoji_click_sticker(const StickerSet *sticker_set, Slice message_text, void choose_animated_emoji_click_sticker(const StickerSet *sticker_set, string message_text,
FullMessageId full_message_id, double start_time, FullMessageId full_message_id, double start_time,
Promise<td_api::object_ptr<td_api::sticker>> &&promise); Promise<td_api::object_ptr<td_api::sticker>> &&promise);
@ -704,8 +706,6 @@ class StickersManager final : public Actor {
void load_reactions(); void load_reactions();
void reload_reactions();
void update_active_reactions(); void update_active_reactions();
td_api::object_ptr<td_api::updateReactions> get_update_reactions_object() const; td_api::object_ptr<td_api::updateReactions> get_update_reactions_object() const;
@ -721,8 +721,6 @@ class StickersManager final : public Actor {
void load_special_sticker_set(SpecialStickerSet &sticker_set); void load_special_sticker_set(SpecialStickerSet &sticker_set);
void reload_special_sticker_set_by_type(SpecialStickerSetType type, bool is_recursive = false);
void reload_special_sticker_set(SpecialStickerSet &sticker_set, int32 hash); void reload_special_sticker_set(SpecialStickerSet &sticker_set, int32 hash);
static void add_sticker_thumbnail(Sticker *s, PhotoSize thumbnail); static void add_sticker_thumbnail(Sticker *s, PhotoSize thumbnail);

View File

@ -341,7 +341,7 @@ void StickersManager::parse_sticker_set(StickerSet *sticker_set, ParserT &parser
vector<string> emojis; vector<string> emojis;
parse(emojis, parser); parse(emojis, parser);
for (auto &emoji : emojis) { for (auto &emoji : emojis) {
auto cleaned_emoji = remove_emoji_modifiers(emoji).str(); auto cleaned_emoji = remove_emoji_modifiers(emoji);
if (!cleaned_emoji.empty()) { if (!cleaned_emoji.empty()) {
auto &sticker_ids = sticker_set->emoji_stickers_map_[cleaned_emoji]; auto &sticker_ids = sticker_set->emoji_stickers_map_[cleaned_emoji];
if (sticker_ids.empty() || sticker_ids.back() != sticker_id) { if (sticker_ids.empty() || sticker_ids.back() != sticker_id) {

View File

@ -2676,22 +2676,6 @@ class GetInlineQueryResultsRequest final : public RequestOnceActor {
} }
}; };
class GetSupportUserRequest final : public RequestActor<> {
UserId user_id_;
void do_run(Promise<Unit> &&promise) final {
user_id_ = td_->contacts_manager_->get_support_user(std::move(promise));
}
void do_send_result() final {
send_result(td_->contacts_manager_->get_user_object(user_id_));
}
public:
GetSupportUserRequest(ActorShared<Td> td, uint64 request_id) : RequestActor(std::move(td), request_id) {
}
};
class SearchBackgroundRequest final : public RequestActor<> { class SearchBackgroundRequest final : public RequestActor<> {
string name_; string name_;
@ -3687,9 +3671,6 @@ void Td::close_impl(bool destroy_flag) {
class Td::DownloadFileCallback final : public FileManager::DownloadCallback { class Td::DownloadFileCallback final : public FileManager::DownloadCallback {
public: public:
void on_progress(FileId file_id) final {
}
void on_download_ok(FileId file_id) final { void on_download_ok(FileId file_id) final {
send_closure(G()->td(), &Td::on_file_download_finished, file_id); send_closure(G()->td(), &Td::on_file_download_finished, file_id);
} }
@ -3701,9 +3682,6 @@ class Td::DownloadFileCallback final : public FileManager::DownloadCallback {
class Td::UploadFileCallback final : public FileManager::UploadCallback { class Td::UploadFileCallback final : public FileManager::UploadCallback {
public: public:
void on_progress(FileId file_id) final {
}
void on_upload_ok(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) final { void on_upload_ok(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) final {
// cancel file upload of the file to allow next upload with the same file to succeed // cancel file upload of the file to allow next upload with the same file to succeed
send_closure(G()->file_manager(), &FileManager::cancel_upload, file_id); send_closure(G()->file_manager(), &FileManager::cancel_upload, file_id);
@ -7766,7 +7744,8 @@ void Td::on_request(uint64 id, td_api::checkPhoneNumberConfirmationCode &request
void Td::on_request(uint64 id, const td_api::getSupportUser &request) { void Td::on_request(uint64 id, const td_api::getSupportUser &request) {
CHECK_IS_USER(); CHECK_IS_USER();
CREATE_NO_ARGS_REQUEST(GetSupportUserRequest); CREATE_REQUEST_PROMISE();
contacts_manager_->get_support_user(std::move(promise));
} }
void Td::on_request(uint64 id, const td_api::getBackgrounds &request) { void Td::on_request(uint64 id, const td_api::getBackgrounds &request) {

View File

@ -38,10 +38,12 @@
#include "td/telegram/PollId.h" #include "td/telegram/PollId.h"
#include "td/telegram/PollManager.h" #include "td/telegram/PollManager.h"
#include "td/telegram/PrivacyManager.h" #include "td/telegram/PrivacyManager.h"
#include "td/telegram/PublicDialogType.h"
#include "td/telegram/ScheduledServerMessageId.h" #include "td/telegram/ScheduledServerMessageId.h"
#include "td/telegram/SecretChatId.h" #include "td/telegram/SecretChatId.h"
#include "td/telegram/SecretChatsManager.h" #include "td/telegram/SecretChatsManager.h"
#include "td/telegram/ServerMessageId.h" #include "td/telegram/ServerMessageId.h"
#include "td/telegram/SpecialStickerSetType.h"
#include "td/telegram/StateManager.h" #include "td/telegram/StateManager.h"
#include "td/telegram/StickerSetId.h" #include "td/telegram/StickerSetId.h"
#include "td/telegram/StickersManager.h" #include "td/telegram/StickersManager.h"
@ -181,6 +183,26 @@ void UpdatesManager::tear_down() {
LOG(DEBUG) << "Have " << being_processed_updates_ << " unprocessed updates to apply"; LOG(DEBUG) << "Have " << being_processed_updates_ << " unprocessed updates to apply";
} }
void UpdatesManager::start_up() {
class StateCallback final : public StateManager::Callback {
public:
explicit StateCallback(ActorId<UpdatesManager> parent) : parent_(std::move(parent)) {
}
bool on_online(bool is_online) final {
if (is_online) {
send_closure(parent_, &UpdatesManager::try_reload_data);
}
return parent_.is_alive();
}
private:
ActorId<UpdatesManager> parent_;
};
send_closure(G()->state_manager(), &StateManager::add_callback, make_unique<StateCallback>(actor_id(this)));
next_data_reload_time_ = Time::now() - 1;
}
void UpdatesManager::hangup_shared() { void UpdatesManager::hangup_shared() {
ref_cnt_--; ref_cnt_--;
if (ref_cnt_ == 0) { if (ref_cnt_ == 0) {
@ -1557,15 +1579,65 @@ void UpdatesManager::after_get_difference() {
<< postponed_pts_updates_.size() << " pending pts updates"; << postponed_pts_updates_.size() << " pending pts updates";
} }
td_->animations_manager_->after_get_difference();
td_->contacts_manager_->after_get_difference();
td_->download_manager_->after_get_difference(); td_->download_manager_->after_get_difference();
td_->inline_queries_manager_->after_get_difference(); td_->inline_queries_manager_->after_get_difference();
td_->messages_manager_->after_get_difference(); td_->messages_manager_->after_get_difference();
td_->notification_settings_manager_->after_get_difference(); td_->notification_settings_manager_->after_get_difference();
td_->stickers_manager_->after_get_difference();
send_closure_later(td_->notification_manager_actor_, &NotificationManager::after_get_difference); send_closure_later(td_->notification_manager_actor_, &NotificationManager::after_get_difference);
send_closure(G()->state_manager(), &StateManager::on_synchronized, true); send_closure(G()->state_manager(), &StateManager::on_synchronized, true);
try_reload_data();
}
void UpdatesManager::schedule_data_reload() {
if (data_reload_timeout_.has_timeout()) {
return;
}
auto timeout = next_data_reload_time_ - Time::now();
LOG(INFO) << "Schedule data reload in " << timeout;
data_reload_timeout_.set_callback(std::move(try_reload_data_static));
data_reload_timeout_.set_callback_data(static_cast<void *>(td_));
data_reload_timeout_.set_timeout_in(timeout);
}
void UpdatesManager::try_reload_data_static(void *td) {
CHECK(td != nullptr);
if (G()->close_flag()) {
return;
}
static_cast<Td *>(td)->updates_manager_->try_reload_data();
}
void UpdatesManager::try_reload_data() {
if (td_->auth_manager_->is_bot() || running_get_difference_ || !td_->is_online()) {
return;
}
auto now = Time::now();
if (now < next_data_reload_time_) {
schedule_data_reload();
return;
}
next_data_reload_time_ = now + Random::fast(3000, 4200);
LOG(INFO) << "Reload data";
td_->animations_manager_->get_saved_animations(Auto());
td_->contacts_manager_->reload_created_public_dialogs(PublicDialogType::HasUsername, Auto());
td_->contacts_manager_->reload_created_public_dialogs(PublicDialogType::IsLocationBased, Auto());
td_->notification_settings_manager_->reload_saved_ringtones(Auto());
td_->stickers_manager_->reload_reactions();
td_->stickers_manager_->get_installed_sticker_sets(false, Auto());
td_->stickers_manager_->get_installed_sticker_sets(true, Auto());
td_->stickers_manager_->get_featured_sticker_sets(0, 1000, Auto());
td_->stickers_manager_->get_recent_stickers(false, Auto());
td_->stickers_manager_->get_recent_stickers(true, Auto());
td_->stickers_manager_->get_favorite_stickers(Auto());
td_->stickers_manager_->reload_special_sticker_set_by_type(SpecialStickerSetType::animated_emoji());
td_->stickers_manager_->reload_special_sticker_set_by_type(SpecialStickerSetType::animated_emoji_click());
schedule_data_reload();
} }
void UpdatesManager::on_pending_updates(vector<tl_object_ptr<telegram_api::Update>> &&updates, int32 seq_begin, void UpdatesManager::on_pending_updates(vector<tl_object_ptr<telegram_api::Update>> &&updates, int32 seq_begin,

View File

@ -221,12 +221,17 @@ class UpdatesManager final : public Actor {
int32 retry_time_ = 1; int32 retry_time_ = 1;
Timeout retry_timeout_; Timeout retry_timeout_;
double next_data_reload_time_ = 0.0;
Timeout data_reload_timeout_;
bool running_get_difference_ = false; bool running_get_difference_ = false;
int32 last_get_difference_pts_ = 0; int32 last_get_difference_pts_ = 0;
int32 last_get_difference_qts_ = 0; int32 last_get_difference_qts_ = 0;
int32 min_postponed_update_pts_ = 0; int32 min_postponed_update_pts_ = 0;
int32 min_postponed_update_qts_ = 0; int32 min_postponed_update_qts_ = 0;
void start_up() final;
void tear_down() final; void tear_down() final;
void hangup_shared() final; void hangup_shared() final;
@ -331,6 +336,12 @@ class UpdatesManager final : public Actor {
void after_get_difference(); void after_get_difference();
void schedule_data_reload();
static void try_reload_data_static(void *td);
void try_reload_data();
static bool have_update_pts_changed(const vector<tl_object_ptr<telegram_api::Update>> &updates); static bool have_update_pts_changed(const vector<tl_object_ptr<telegram_api::Update>> &updates);
static bool check_pts_update_dialog_id(DialogId dialog_id); static bool check_pts_update_dialog_id(DialogId dialog_id);

View File

@ -50,6 +50,7 @@ enum class Version : int32 {
AddInviteLinksRequiringApproval, AddInviteLinksRequiringApproval,
AddKeyboardButtonFlags, // 35 AddKeyboardButtonFlags, // 35
AddAudioFlags, AddAudioFlags,
UseServerForwardAsCopy,
Next Next
}; };

View File

@ -162,8 +162,7 @@ SecretInputMedia VideoNotesManager::get_secret_input_media(FileId video_note_fil
const VideoNote *video_note = get_video_note(video_note_file_id); const VideoNote *video_note = get_video_note(video_note_file_id);
CHECK(video_note != nullptr); CHECK(video_note != nullptr);
auto file_view = td_->file_manager_->get_file_view(video_note_file_id); auto file_view = td_->file_manager_->get_file_view(video_note_file_id);
auto &encryption_key = file_view.encryption_key(); if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty()) {
if (!file_view.is_encrypted_secret() || encryption_key.empty()) {
return SecretInputMedia{}; return SecretInputMedia{};
} }
if (file_view.has_remote_location()) { if (file_view.has_remote_location()) {
@ -179,12 +178,14 @@ SecretInputMedia VideoNotesManager::get_secret_input_media(FileId video_note_fil
attributes.push_back(make_tl_object<secret_api::documentAttributeVideo66>( attributes.push_back(make_tl_object<secret_api::documentAttributeVideo66>(
secret_api::documentAttributeVideo66::ROUND_MESSAGE_MASK, true, video_note->duration, secret_api::documentAttributeVideo66::ROUND_MESSAGE_MASK, true, video_note->duration,
video_note->dimensions.width, video_note->dimensions.height)); video_note->dimensions.width, video_note->dimensions.height));
return SecretInputMedia{
std::move(input_file), return {std::move(input_file),
make_tl_object<secret_api::decryptedMessageMediaDocument>( std::move(thumbnail),
std::move(thumbnail), video_note->thumbnail.dimensions.width, video_note->thumbnail.dimensions.height, video_note->thumbnail.dimensions,
"video/mp4", narrow_cast<int32>(file_view.size()), BufferSlice(encryption_key.key_slice()), "video/mp4",
BufferSlice(encryption_key.iv_slice()), std::move(attributes), "")}; file_view,
std::move(attributes),
string()};
} }
tl_object_ptr<telegram_api::InputMedia> VideoNotesManager::get_input_media( tl_object_ptr<telegram_api::InputMedia> VideoNotesManager::get_input_media(

View File

@ -208,8 +208,7 @@ SecretInputMedia VideosManager::get_secret_input_media(FileId video_file_id,
const Video *video = get_video(video_file_id); const Video *video = get_video(video_file_id);
CHECK(video != nullptr); CHECK(video != nullptr);
auto file_view = td_->file_manager_->get_file_view(video_file_id); auto file_view = td_->file_manager_->get_file_view(video_file_id);
auto &encryption_key = file_view.encryption_key(); if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty()) {
if (!file_view.is_encrypted_secret() || encryption_key.empty()) {
return SecretInputMedia{}; return SecretInputMedia{};
} }
if (file_view.has_remote_location()) { if (file_view.has_remote_location()) {
@ -221,12 +220,17 @@ SecretInputMedia VideosManager::get_secret_input_media(FileId video_file_id,
if (video->thumbnail.file_id.is_valid() && thumbnail.empty()) { if (video->thumbnail.file_id.is_valid() && thumbnail.empty()) {
return {}; return {};
} }
return SecretInputMedia{ vector<tl_object_ptr<secret_api::DocumentAttribute>> attributes;
std::move(input_file), attributes.emplace_back(make_tl_object<secret_api::documentAttributeVideo>(video->duration, video->dimensions.width,
make_tl_object<secret_api::decryptedMessageMediaVideo>( video->dimensions.height));
std::move(thumbnail), video->thumbnail.dimensions.width, video->thumbnail.dimensions.height, video->duration,
video->mime_type, video->dimensions.width, video->dimensions.height, narrow_cast<int32>(file_view.size()), return {std::move(input_file),
BufferSlice(encryption_key.key_slice()), BufferSlice(encryption_key.iv_slice()), caption)}; std::move(thumbnail),
video->thumbnail.dimensions,
video->mime_type,
file_view,
std::move(attributes),
caption};
} }
tl_object_ptr<telegram_api::InputMedia> VideosManager::get_input_media( tl_object_ptr<telegram_api::InputMedia> VideosManager::get_input_media(

View File

@ -133,8 +133,7 @@ SecretInputMedia VoiceNotesManager::get_secret_input_media(FileId voice_file_id,
auto *voice_note = get_voice_note(voice_file_id); auto *voice_note = get_voice_note(voice_file_id);
CHECK(voice_note != nullptr); CHECK(voice_note != nullptr);
auto file_view = td_->file_manager_->get_file_view(voice_file_id); auto file_view = td_->file_manager_->get_file_view(voice_file_id);
auto &encryption_key = file_view.encryption_key(); if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty()) {
if (!file_view.is_encrypted_secret() || encryption_key.empty()) {
return SecretInputMedia{}; return SecretInputMedia{};
} }
if (file_view.has_remote_location()) { if (file_view.has_remote_location()) {
@ -147,11 +146,9 @@ SecretInputMedia VoiceNotesManager::get_secret_input_media(FileId voice_file_id,
attributes.push_back(make_tl_object<secret_api::documentAttributeAudio>( attributes.push_back(make_tl_object<secret_api::documentAttributeAudio>(
secret_api::documentAttributeAudio::VOICE_MASK | secret_api::documentAttributeAudio::WAVEFORM_MASK, secret_api::documentAttributeAudio::VOICE_MASK | secret_api::documentAttributeAudio::WAVEFORM_MASK,
false /*ignored*/, voice_note->duration, "", "", BufferSlice(voice_note->waveform))); false /*ignored*/, voice_note->duration, "", "", BufferSlice(voice_note->waveform)));
return SecretInputMedia{std::move(input_file),
make_tl_object<secret_api::decryptedMessageMediaDocument>( return {std::move(input_file), BufferSlice(), Dimensions(), voice_note->mime_type, file_view,
BufferSlice(), 0, 0, voice_note->mime_type, narrow_cast<int32>(file_view.size()), std::move(attributes), caption};
BufferSlice(encryption_key.key_slice()), BufferSlice(encryption_key.iv_slice()),
std::move(attributes), caption)};
} }
tl_object_ptr<telegram_api::InputMedia> VoiceNotesManager::get_input_media( tl_object_ptr<telegram_api::InputMedia> VoiceNotesManager::get_input_media(

View File

@ -373,9 +373,6 @@ class FileManager final : public FileLoadManager::Callback {
UploadCallback &operator=(const UploadCallback &) = delete; UploadCallback &operator=(const UploadCallback &) = delete;
virtual ~UploadCallback() = default; virtual ~UploadCallback() = default;
virtual void on_progress(FileId file_id) {
}
// After on_upload_ok all uploads of this file will be paused till merge, delete_partial_remote_location or // After on_upload_ok all uploads of this file will be paused till merge, delete_partial_remote_location or
// explicit upload request with the same file_id. // explicit upload request with the same file_id.
// Also upload may be resumed after some other merges. // Also upload may be resumed after some other merges.

View File

@ -305,6 +305,7 @@ set(TDUTILS_TEST_SOURCE
${CMAKE_CURRENT_SOURCE_DIR}/test/ChainScheduler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/ChainScheduler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/ConcurrentHashMap.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/ConcurrentHashMap.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/crypto.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/crypto.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/emoji.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/Enumerator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/Enumerator.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/EpochBasedMemoryReclamation.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/EpochBasedMemoryReclamation.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/filesystem.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/filesystem.cpp

View File

@ -243,7 +243,13 @@ Slice remove_fitzpatrick_modifier(Slice emoji) {
return emoji; return emoji;
} }
Slice remove_emoji_modifiers(Slice emoji) { string remove_emoji_modifiers(Slice emoji) {
string result = emoji.str();
remove_emoji_modifiers_in_place(result);
return result;
}
void remove_emoji_modifiers_in_place(string &emoji) {
static const Slice modifiers[] = {u8"\uFE0F" /* variation selector-16 */, static const Slice modifiers[] = {u8"\uFE0F" /* variation selector-16 */,
u8"\u200D\u2640" /* zero width joiner + female sign */, u8"\u200D\u2640" /* zero width joiner + female sign */,
u8"\u200D\u2642" /* zero width joiner + male sign */, u8"\u200D\u2642" /* zero width joiner + male sign */,
@ -252,21 +258,23 @@ Slice remove_emoji_modifiers(Slice emoji) {
u8"\U0001F3FD" /* emoji modifier fitzpatrick type-4 */, u8"\U0001F3FD" /* emoji modifier fitzpatrick type-4 */,
u8"\U0001F3FE" /* emoji modifier fitzpatrick type-5 */, u8"\U0001F3FE" /* emoji modifier fitzpatrick type-5 */,
u8"\U0001F3FF" /* emoji modifier fitzpatrick type-6 */}; u8"\U0001F3FF" /* emoji modifier fitzpatrick type-6 */};
bool found = true; size_t j = 0;
while (found) { for (size_t i = 0; i < emoji.size();) {
found = false; bool is_found = false;
for (auto &modifier : modifiers) { for (auto &modifier : modifiers) {
if (ends_with(emoji, modifier) && emoji.size() > modifier.size()) { auto length = modifier.size();
emoji.remove_suffix(modifier.size()); if (i + length <= emoji.size() && Slice(&emoji[i], length) == modifier) {
found = true; // skip modifier
i += length;
is_found = true;
break;
} }
} }
if (!is_found) {
emoji[j++] = emoji[i++];
}
} }
return emoji; emoji.resize(j);
}
void remove_emoji_modifiers_in_place(string &emoji) {
emoji.resize(remove_emoji_modifiers(emoji).size());
} }
string remove_emoji_selectors(Slice emoji) { string remove_emoji_selectors(Slice emoji) {

View File

@ -20,10 +20,10 @@ int get_fitzpatrick_modifier(Slice emoji);
// removes all Fitzpatrick modifier from the end of the string // removes all Fitzpatrick modifier from the end of the string
Slice remove_fitzpatrick_modifier(Slice emoji); Slice remove_fitzpatrick_modifier(Slice emoji);
// removes all emoji modifiers from the end of the string // removes all emoji modifiers from the string
Slice remove_emoji_modifiers(Slice emoji); string remove_emoji_modifiers(Slice emoji);
// removes all emoji modifiers from the end of the string in place // removes all emoji modifiers from the string in-place
void remove_emoji_modifiers_in_place(string &emoji); void remove_emoji_modifiers_in_place(string &emoji);
// removes all emoji selectors from the string if it is an emoji // removes all emoji selectors from the string if it is an emoji

125
tdutils/test/emoji.cpp Normal file
View File

@ -0,0 +1,125 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
//
// 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/utils/emoji.h"
#include "td/utils/tests.h"
TEST(Emoji, is_emoji) {
ASSERT_TRUE(!td::is_emoji(""));
ASSERT_TRUE(td::is_emoji("👩🏼‍❤‍💋‍👩🏻"));
ASSERT_TRUE(td::is_emoji("👩🏼‍❤️‍💋‍👩🏻"));
ASSERT_TRUE(!td::is_emoji("👩🏼‍❤️️‍💋‍👩🏻"));
ASSERT_TRUE(td::is_emoji(""));
ASSERT_TRUE(td::is_emoji(""));
ASSERT_TRUE(td::is_emoji("🪗"));
ASSERT_TRUE(td::is_emoji("2"));
ASSERT_TRUE(td::is_emoji("2⃣"));
ASSERT_TRUE(!td::is_emoji(" 2⃣"));
ASSERT_TRUE(!td::is_emoji("2⃣ "));
ASSERT_TRUE(!td::is_emoji(" "));
ASSERT_TRUE(!td::is_emoji(""));
ASSERT_TRUE(!td::is_emoji("1234567890123456789012345678901234567890123456789012345678901234567890"));
ASSERT_TRUE(td::is_emoji("❤️"));
ASSERT_TRUE(td::is_emoji(""));
ASSERT_TRUE(td::is_emoji(""));
ASSERT_TRUE(td::is_emoji("🎄"));
ASSERT_TRUE(td::is_emoji("🧑‍🎄"));
}
static void test_get_fitzpatrick_modifier(td::string emoji, int result) {
ASSERT_EQ(result, td::get_fitzpatrick_modifier(emoji));
}
TEST(Emoji, get_fitzpatrick_modifier) {
test_get_fitzpatrick_modifier("", 0);
test_get_fitzpatrick_modifier("👩🏼‍❤‍💋‍👩🏻", 2);
test_get_fitzpatrick_modifier("👩🏼‍❤️‍💋‍👩🏻", 2);
test_get_fitzpatrick_modifier("👋", 0);
test_get_fitzpatrick_modifier("👋🏻", 2);
test_get_fitzpatrick_modifier("👋🏼", 3);
test_get_fitzpatrick_modifier("👋🏽", 4);
test_get_fitzpatrick_modifier("👋🏾", 5);
test_get_fitzpatrick_modifier("👋🏿", 6);
test_get_fitzpatrick_modifier("🏻", 2);
test_get_fitzpatrick_modifier("🏼", 3);
test_get_fitzpatrick_modifier("🏽", 4);
test_get_fitzpatrick_modifier("🏾", 5);
test_get_fitzpatrick_modifier("🏿", 6);
test_get_fitzpatrick_modifier("", 0);
test_get_fitzpatrick_modifier("", 0);
test_get_fitzpatrick_modifier("🪗", 0);
test_get_fitzpatrick_modifier("2", 0);
test_get_fitzpatrick_modifier("2⃣", 0);
test_get_fitzpatrick_modifier("❤️", 0);
test_get_fitzpatrick_modifier("", 0);
test_get_fitzpatrick_modifier("", 0);
test_get_fitzpatrick_modifier("🎄", 0);
test_get_fitzpatrick_modifier("🧑‍🎄", 0);
}
static void test_remove_emoji_modifiers(td::string emoji, const td::string &result) {
ASSERT_STREQ(result, td::remove_emoji_modifiers(emoji));
td::remove_emoji_modifiers_in_place(emoji);
ASSERT_STREQ(result, emoji);
ASSERT_STREQ(emoji, td::remove_emoji_modifiers(emoji));
}
TEST(Emoji, remove_emoji_modifiers) {
test_remove_emoji_modifiers("", "");
test_remove_emoji_modifiers("👩🏼‍❤‍💋‍👩🏻", "👩‍❤‍💋‍👩");
test_remove_emoji_modifiers("👩🏼‍❤️‍💋‍👩🏻", "👩‍❤‍💋‍👩");
test_remove_emoji_modifiers("👋🏻", "👋");
test_remove_emoji_modifiers("👋🏼", "👋");
test_remove_emoji_modifiers("👋🏽", "👋");
test_remove_emoji_modifiers("👋🏾", "👋");
test_remove_emoji_modifiers("👋🏿", "👋");
test_remove_emoji_modifiers("🏻", "");
test_remove_emoji_modifiers("🏼", "");
test_remove_emoji_modifiers("🏽", "");
test_remove_emoji_modifiers("🏾", "");
test_remove_emoji_modifiers("🏿", "");
test_remove_emoji_modifiers("", "");
test_remove_emoji_modifiers("", "");
test_remove_emoji_modifiers("🪗", "🪗");
test_remove_emoji_modifiers("2", "2⃣");
test_remove_emoji_modifiers("2⃣", "2⃣");
test_remove_emoji_modifiers("❤️", "");
test_remove_emoji_modifiers("", "");
test_remove_emoji_modifiers("", "");
test_remove_emoji_modifiers("🎄", "🎄");
test_remove_emoji_modifiers("🧑‍🎄", "🧑‍🎄");
}
static void test_remove_emoji_selectors(td::string emoji, const td::string &result) {
ASSERT_STREQ(result, td::remove_emoji_selectors(result));
ASSERT_STREQ(result, td::remove_emoji_selectors(emoji));
}
TEST(Emoji, remove_emoji_selectors) {
test_remove_emoji_selectors("", "");
test_remove_emoji_selectors("👩🏼‍❤‍💋‍👩🏻", "👩🏼‍❤‍💋‍👩🏻");
test_remove_emoji_selectors("👩🏼‍❤️‍💋‍👩🏻", "👩🏼‍❤‍💋‍👩🏻");
test_remove_emoji_selectors("👋🏻", "👋🏻");
test_remove_emoji_selectors("👋🏼", "👋🏼");
test_remove_emoji_selectors("👋🏽", "👋🏽");
test_remove_emoji_selectors("👋🏾", "👋🏾");
test_remove_emoji_selectors("👋🏿", "👋🏿");
test_remove_emoji_selectors("🏻", "🏻");
test_remove_emoji_selectors("🏼", "🏼");
test_remove_emoji_selectors("🏽", "🏽");
test_remove_emoji_selectors("🏾", "🏾");
test_remove_emoji_selectors("🏿", "🏿");
test_remove_emoji_selectors("", "");
test_remove_emoji_selectors("", "");
test_remove_emoji_selectors("🪗", "🪗");
test_remove_emoji_selectors("2", "2⃣");
test_remove_emoji_selectors("2⃣", "2⃣");
test_remove_emoji_selectors("❤️", "");
test_remove_emoji_selectors("", "");
test_remove_emoji_selectors("", "");
test_remove_emoji_selectors("🎄", "🎄");
test_remove_emoji_selectors("🧑‍🎄", "🧑‍🎄");
}

View File

@ -24,24 +24,24 @@ TEST(Misc, clean_filename) {
test_clean_filename("!@#$%^&*()_+-=[]{;|:\"}'<>?,.`~", "!@#$%^ ()_+-=[]{; } ,.~"); test_clean_filename("!@#$%^&*()_+-=[]{;|:\"}'<>?,.`~", "!@#$%^ ()_+-=[]{; } ,.~");
test_clean_filename("!@#$%^&*()_+-=[]{}\\|:\";'<>?,.`~", "; ,.~"); test_clean_filename("!@#$%^&*()_+-=[]{}\\|:\";'<>?,.`~", "; ,.~");
test_clean_filename("عرفها بعد قد. هذا مع تاريخ اليميني واندونيسيا،, لعدم تاريخ لهيمنة الى", test_clean_filename("عرفها بعد قد. هذا مع تاريخ اليميني واندونيسيا،, لعدم تاريخ لهيمنة الى",
"عرفها بعد قد.هذا مع تاريخ اليميني"); "عرفها بعد قد.هذا مع تاريخ الي");
test_clean_filename( test_clean_filename(
"012345678901234567890123456789012345678901234567890123456789adsasdasdsaa.01234567890123456789asdasdasdasd", "012345678901234567890123456789012345678901234567890123456789adsasdasdsaa.01234567890123456789asdasdasdasd",
"012345678901234567890123456789012345678901234567890123456789.01234567890123456789"); "012345678901234567890123456789012345678901234567890123456789adsa.0123456789012345");
test_clean_filename( test_clean_filename(
"01234567890123456789012345678901234567890123456789<>*?: <>*?:0123456789adsasdasdsaa. " "01234567890123456789012345678901234567890123456789adsa<>*?: <>*?:0123456789adsasdasdsaa. "
"0123456789`<><<>><><>0123456789asdasdasdasd", "0123456789`<><<>><><>0123456789asdasdasdasd",
"01234567890123456789012345678901234567890123456789.0123456789"); "01234567890123456789012345678901234567890123456789adsa.0123456789");
test_clean_filename( test_clean_filename(
"01234567890123456789012345678901234567890123456789<>*?: <>*?:0123456789adsasdasdsaa. " "012345678901234567890123456789012345678901234567890123<>*?: <>*?:0123456789adsasdasdsaa. "
"0123456789`<><><>0123456789asdasdasdasd", "0123456789`<>0123456789asdasdasdasd",
"01234567890123456789012345678901234567890123456789.0123456789 012"); "012345678901234567890123456789012345678901234567890123.0123456789 012");
test_clean_filename("C:/document.tar.gz", "document.tar.gz"); test_clean_filename("C:/document.tar.gz", "document.tar.gz");
test_clean_filename("test....", "test"); test_clean_filename("test....", "test");
test_clean_filename("....test", "test"); test_clean_filename("....test", "test");
test_clean_filename("test.exe....", "test.exe"); // extension has changed test_clean_filename("test.exe....", "test.exe"); // extension has changed
test_clean_filename("test.exe01234567890123456789....", test_clean_filename("test.exe01234567890123456789....",
"test.exe01234567890123456789"); // extension may be more than 20 characters "test.exe01234567890123456789"); // extension may be more than 16 characters
test_clean_filename("....test....asdf", "test.asdf"); test_clean_filename("....test....asdf", "test.asdf");
test_clean_filename("കറുപ്പ്.txt", "കറപപ.txt"); test_clean_filename("കറുപ്പ്.txt", "കറപപ.txt");
} }

View File

@ -11,7 +11,6 @@
#include "td/utils/bits.h" #include "td/utils/bits.h"
#include "td/utils/CancellationToken.h" #include "td/utils/CancellationToken.h"
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/emoji.h"
#include "td/utils/ExitGuard.h" #include "td/utils/ExitGuard.h"
#include "td/utils/Hash.h" #include "td/utils/Hash.h"
#include "td/utils/HashMap.h" #include "td/utils/HashMap.h"
@ -1215,27 +1214,6 @@ TEST(Misc, uname) {
ASSERT_TRUE(!first_version.empty()); ASSERT_TRUE(!first_version.empty());
} }
TEST(Misc, is_emoji) {
ASSERT_TRUE(td::is_emoji("👩🏼‍❤‍💋‍👩🏻"));
ASSERT_TRUE(td::is_emoji("👩🏼‍❤️‍💋‍👩🏻"));
ASSERT_TRUE(!td::is_emoji("👩🏼‍❤️️‍💋‍👩🏻"));
ASSERT_TRUE(td::is_emoji(""));
ASSERT_TRUE(td::is_emoji(""));
ASSERT_TRUE(td::is_emoji("🪗"));
ASSERT_TRUE(td::is_emoji("2"));
ASSERT_TRUE(td::is_emoji("2⃣"));
ASSERT_TRUE(!td::is_emoji(" 2⃣"));
ASSERT_TRUE(!td::is_emoji("2⃣ "));
ASSERT_TRUE(!td::is_emoji(" "));
ASSERT_TRUE(!td::is_emoji(""));
ASSERT_TRUE(!td::is_emoji("1234567890123456789012345678901234567890123456789012345678901234567890"));
ASSERT_TRUE(td::is_emoji("❤️"));
ASSERT_TRUE(td::is_emoji(""));
ASSERT_TRUE(td::is_emoji(""));
ASSERT_TRUE(td::is_emoji("🎄"));
ASSERT_TRUE(td::is_emoji("🧑‍🎄"));
}
TEST(Misc, serialize) { TEST(Misc, serialize) {
td::int32 x = 1; td::int32 x = 1;
ASSERT_EQ(td::base64_encode(td::serialize(x)), td::base64_encode(td::string("\x01\x00\x00\x00", 4))); ASSERT_EQ(td::base64_encode(td::serialize(x)), td::base64_encode(td::string("\x01\x00\x00\x00", 4)));