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/SecretChatDb.cpp
td/telegram/SecretChatsManager.cpp
td/telegram/SecretInputMedia.cpp
td/telegram/SecureManager.cpp
td/telegram/SecureStorage.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);
CHECK(animation != nullptr);
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() || encryption_key.empty()) {
if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty()) {
return SecretInputMedia{};
}
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>());
return SecretInputMedia{
std::move(input_file),
make_tl_object<secret_api::decryptedMessageMediaDocument>(
std::move(thumbnail), animation->thumbnail.dimensions.width, animation->thumbnail.dimensions.height,
animation->mime_type, narrow_cast<int32>(file_view.size()), BufferSlice(encryption_key.key_slice()),
BufferSlice(encryption_key.iv_slice()), std::move(attributes), caption)};
return {std::move(input_file),
std::move(thumbnail),
animation->thumbnail.dimensions,
animation->mime_type,
file_view,
std::move(attributes),
caption};
}
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;
}
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 {
if (td_->auth_manager_->is_bot()) {
return;

View File

@ -91,8 +91,6 @@ class AnimationsManager final : public Actor {
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;
private:

View File

@ -210,8 +210,7 @@ SecretInputMedia AudiosManager::get_secret_input_media(FileId audio_file_id,
auto *audio = get_audio(audio_file_id);
CHECK(audio != nullptr);
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() || encryption_key.empty()) {
if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty()) {
return SecretInputMedia{};
}
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,
false /*ignored*/, audio->duration, audio->title, audio->performer, BufferSlice()));
return SecretInputMedia{
std::move(input_file),
make_tl_object<secret_api::decryptedMessageMediaDocument>(
std::move(thumbnail), audio->thumbnail.dimensions.width, audio->thumbnail.dimensions.height, audio->mime_type,
narrow_cast<int32>(file_view.size()), BufferSlice(encryption_key.key_slice()),
BufferSlice(encryption_key.iv_slice()), std::move(attributes), caption)};
return {std::move(input_file),
std::move(thumbnail),
audio->thumbnail.dimensions,
audio->mime_type,
file_view,
std::move(attributes),
caption};
}
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) {
if (set_option(name, PSLICE() << "I" << value)) {
if (set_option(name, PSLICE() << 'I' << value)) {
on_option_updated(name);
}
}
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);
}
}
@ -73,32 +73,32 @@ bool ConfigShared::get_option_boolean(Slice name, bool default_value) const {
if (value == "Bfalse") {
return false;
}
LOG(ERROR) << "Found \"" << value << "\" instead of boolean option";
LOG(ERROR) << "Found \"" << value << "\" instead of boolean option " << name;
return default_value;
}
int64 ConfigShared::get_option_integer(Slice name, int64 default_value) const {
auto str_value = get_option(name);
if (str_value.empty()) {
auto value = get_option(name);
if (value.empty()) {
return default_value;
}
if (str_value[0] != 'I') {
LOG(ERROR) << "Found \"" << str_value << "\" instead of integer option";
if (value[0] != 'I') {
LOG(ERROR) << "Found \"" << value << "\" instead of integer option " << name;
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 {
auto str_value = get_option(name);
if (str_value.empty()) {
auto value = get_option(name);
if (value.empty()) {
return default_value;
}
if (str_value[0] != 'S') {
LOG(ERROR) << "Found \"" << str_value << "\" instead of string option";
if (value[0] != 'S') {
LOG(ERROR) << "Found \"" << value << "\" instead of string option " << name;
return default_value;
}
return str_value.substr(1);
return value.substr(1);
}
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 {
Promise<Unit> promise_;
Promise<UserId> promise_;
public:
explicit GetSupportUserQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
explicit GetSupportUserQuery(Promise<UserId> &&promise) : promise_(std::move(promise)) {
}
void send() {
@ -2943,9 +2943,10 @@ class GetSupportUserQuery final : public Td::ResultHandler {
auto ptr = result_ptr.move_as_ok();
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 {
@ -4040,6 +4041,7 @@ void ContactsManager::Channel::store(StorerT &storer) const {
STORE_FLAG(is_fake);
STORE_FLAG(is_gigagroup);
STORE_FLAG(noforwards);
STORE_FLAG(can_be_deleted); // 25
END_STORE_FLAGS();
store(status, storer);
@ -4110,6 +4112,7 @@ void ContactsManager::Channel::parse(ParserT &parser) {
PARSE_FLAG(is_fake);
PARSE_FLAG(is_gigagroup);
PARSE_FLAG(noforwards);
PARSE_FLAG(can_be_deleted);
END_PARSE_FLAGS();
if (use_new_rights) {
@ -6881,7 +6884,7 @@ void ContactsManager::delete_channel(ChannelId channel_id, Promise<Unit> &&promi
if (c == nullptr) {
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"));
}
@ -8397,8 +8400,7 @@ DialogId ContactsManager::get_dialog_id(const tl_object_ptr<telegram_api::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,
bool expect_support) {
void ContactsManager::on_get_user(tl_object_ptr<telegram_api::User> &&user_ptr, const char *source, bool is_me) {
LOG(DEBUG) << "Receive from " << source << ' ' << to_string(user_ptr);
int32 constructor_id = user_ptr->get_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 is_received = (flags & USER_FLAG_IS_INACCESSIBLE) == 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 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)
<< "Receive not bot " << user_id << " which can't join groups from " << source;
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->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 ||
(!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),
channel_full->bot_user_ids, true);
update_channel(c, channel_id);
channel_full->is_update_channel_full_sent = 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_));
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(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));
if (chat_full->description != 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));
// 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));
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->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;
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;
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->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");
}
@ -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,
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()) {
photo.minithumbnail.clear();
}
@ -13513,6 +13521,20 @@ void ContactsManager::on_update_chat_photo(Chat *c, DialogPhoto &&photo) {
c->photo = std::move(photo);
c->is_photo_changed = 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,
tl_object_ptr<telegram_api::ChatPhoto> &&chat_photo_ptr) {
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()) {
photo.minithumbnail.clear();
}
@ -13642,6 +13667,24 @@ void ContactsManager::on_update_channel_photo(Channel *c, DialogPhoto &&photo) {
c->photo = std::move(photo);
c->is_photo_changed = 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;
}
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) {
auto channel_full = get_channel_full_const(channel_id);
if (channel_full == nullptr) {
@ -14875,17 +14930,6 @@ int32 ContactsManager::get_channel_slow_mode_delay(ChannelId channel_id) {
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 {
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,
std::move(promise));
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,
td_api::make_object<td_api::chatMemberStatusBanned>(banned_until_date),
std::move(promise));
@ -16710,26 +16755,35 @@ tl_object_ptr<td_api::chatInviteLinkInfo> ContactsManager::get_chat_invite_link_
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()) {
promise.set_value(Unit());
return support_user_id_;
return promise.set_value(get_user_object(support_user_id_));
}
td_->create_handler<GetSupportUserQuery>(std::move(promise))->send();
return UserId();
auto query_promise = PromiseCreator::lambda(
[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() {
if (td_->auth_manager_->is_bot()) {
return;
}
get_user(get_my_id(), 3, Promise<Unit>());
void ContactsManager::on_get_support_user(UserId user_id, Promise<td_api::object_ptr<td_api::user>> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
if (td_->is_online()) {
reload_created_public_dialogs(PublicDialogType::HasUsername, Promise<td_api::object_ptr<td_api::chats>>());
reload_created_public_dialogs(PublicDialogType::IsLocationBased, Promise<td_api::object_ptr<td_api::chats>>());
const User *u = get_user(user_id);
if (u == nullptr) {
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 {

View File

@ -151,8 +151,7 @@ class ContactsManager final : public Actor {
void reload_contacts(bool force);
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_user(tl_object_ptr<telegram_api::User> &&user, const char *source, bool is_me = false);
void on_get_users(vector<tl_object_ptr<telegram_api::User>> &&users, const char *source);
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 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_inactive_channels(Promise<Unit> &&promise);
@ -535,9 +536,9 @@ class ContactsManager final : public Actor {
int32 get_channel_participant_count(ChannelId channel_id) const;
bool get_channel_sign_messages(ChannelId channel_id) const;
bool get_channel_has_linked_channel(ChannelId channel_id) const;
bool get_channel_can_be_deleted(ChannelId channel_id) const;
ChannelId get_channel_linked_channel_id(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);
@ -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);
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 after_get_difference();
void get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const;
static tl_object_ptr<td_api::dateRange> convert_date_range(
@ -835,6 +834,7 @@ class ContactsManager final : public Actor {
bool sign_messages = false;
bool is_slow_mode_enabled = false;
bool noforwards = false;
bool can_be_deleted = false;
bool is_megagroup = false;
bool is_gigagroup = false;
@ -1213,6 +1213,7 @@ class ContactsManager final : public Actor {
DialogParticipantStatus get_channel_permissions(const Channel *c) const;
static bool get_channel_sign_messages(const Channel *c);
static bool get_channel_has_linked_channel(const Channel *c);
static bool get_channel_can_be_deleted(const Channel *c);
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,
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, 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_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);
@ -1275,7 +1276,7 @@ class ContactsManager final : public Actor {
void on_update_channel_photo(Channel *c, ChannelId channel_id,
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);
void on_update_channel_username(Channel *c, ChannelId channel_id, string &&username);
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,
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 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,
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_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,
ChannelType channel_type) {
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) {
case td_api::chatMemberStatusCreator::ID: {
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: {
auto st = static_cast<const td_api::chatMemberStatusRestricted *>(status.get());
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:
return DialogParticipantStatus::Left();
case td_api::chatMemberStatusBanned::ID: {
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:
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);
CHECK(document != nullptr);
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() || encryption_key.empty()) {
if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty()) {
return SecretInputMedia{};
}
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()) {
attributes.push_back(make_tl_object<secret_api::documentAttributeFilename>(document->file_name));
}
return SecretInputMedia{
std::move(input_file),
make_tl_object<secret_api::decryptedMessageMediaDocument>(
std::move(thumbnail), document->thumbnail.dimensions.width, document->thumbnail.dimensions.height,
document->mime_type, narrow_cast<int32>(file_view.size()), BufferSlice(encryption_key.key_slice()),
BufferSlice(encryption_key.iv_slice()), std::move(attributes), caption)};
return {std::move(input_file),
std::move(thumbnail),
document->thumbnail.dimensions,
document->mime_type,
file_view,
std::move(attributes),
caption};
}
tl_object_ptr<telegram_api::InputMedia> DocumentsManager::get_input_media(

View File

@ -1647,8 +1647,12 @@ void GroupCallManager::on_get_group_call_participants(
if (is_load) {
auto *group_call_participants = add_group_call_participants(input_group_call_id);
if (group_call_participants->next_offset == 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) {
bool need_update = false;
@ -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_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) {
GroupCallParticipant participant(group_call_participant, version);
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_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 = [&] {
while (!pending_mute_updates.empty()) {
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,
const GroupCallParticipant &participant,
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) {
return real_order;
}
@ -2106,7 +2115,7 @@ void GroupCallManager::process_group_call_participants(
}
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) {
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;
@ -4122,9 +4131,13 @@ 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();
try_clear_group_call_participants(input_group_call_id);
if (!group_call->need_rejoin) {
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");
}
}
}
void GroupCallManager::discard_group_call(GroupCallId group_call_id, Promise<Unit> &&promise) {
TRY_RESULT_PROMISE(promise, input_group_call_id, get_input_group_call_id(group_call_id));

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_;
}
GroupCallParticipantOrder GroupCallParticipant::get_real_order(bool can_self_unmute, bool joined_date_asc,
bool keep_active_date) const {
GroupCallParticipantOrder GroupCallParticipant::get_real_order(bool can_self_unmute, bool joined_date_asc) const {
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;
}
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);
}
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 {
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);
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 {
return dialog_id.is_valid();

View File

@ -667,7 +667,7 @@ class MessageDice final : public MessageContent {
MessageDice() = default;
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 {
@ -2100,10 +2100,10 @@ Result<InputMessageContent> get_input_message_content(
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()) {
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:
return td->poll_manager_->has_input_media(static_cast<const MessagePoll *>(content)->poll_id);
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(
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) {
if (!can_have_input_media(td, content)) {
if (!can_have_input_media(td, content, false)) {
return nullptr;
}
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) {
CHECK(content != nullptr);
if (copy_options.send_copy) {
CHECK(type == MessageContentDupType::Copy);
CHECK(type == MessageContentDupType::Copy || type == MessageContentDupType::ServerCopy);
}
if (type != MessageContentDupType::Forward && type != MessageContentDupType::SendViaBot &&
!can_have_input_media(td, content)) {
!can_have_input_media(td, content, type == MessageContentDupType::ServerCopy)) {
return nullptr;
}
@ -4382,7 +4382,8 @@ unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const
if (to_secret) {
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()) {
case MessageContentType::Animation: {
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);
}
case MessageContentType::Poll:
if (type == MessageContentDupType::Copy) {
if (type == MessageContentDupType::Copy || type == MessageContentDupType::ServerCopy) {
return make_unique<MessagePoll>(
td->poll_manager_->dup_poll(static_cast<const MessagePoll *>(content)->poll_id));
} 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,
Slice emoji, string data) {
string &&emoji, string &&data) {
if (content->get_type() != MessageContentType::Text) {
return;
}
emoji = remove_emoji_modifiers(emoji);
remove_emoji_modifiers_in_place(emoji);
auto &text = static_cast<const MessageText *>(content)->text;
if (!text.entities.empty() || remove_emoji_modifiers(text.text) != emoji) {
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()) {
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(
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,
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,
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,
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);
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);

View File

@ -26,6 +26,17 @@ struct MessageCopyOptions {
MessageCopyOptions() = default;
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) {

View File

@ -4545,8 +4545,6 @@ class ResolveUsernameQuery final : public Td::ResultHandler {
class MessagesManager::UploadMediaCallback final : public FileManager::UploadCallback {
public:
void on_progress(FileId file_id) 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),
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))};
auto *m = get_message_force(full_message_id, "on_dialog_action");
if (m != nullptr) {
on_message_content_animated_emoji_clicked(m->content.get(), full_message_id, td_, clicking_info.emoji,
std::move(clicking_info.data));
on_message_content_animated_emoji_clicked(m->content.get(), full_message_id, td_,
std::move(clicking_info.emoji), std::move(clicking_info.data));
}
}
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) {
TRY_STATUS_PROMISE(promise, G()->close_status());
LOG(DEBUG) << "Receive " << messages.size() << " 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);
}
promise.set_value(Unit());
@ -15138,7 +15136,7 @@ void MessagesManager::remove_dialog_mention_notifications(Dialog *d) {
CHECK(m != nullptr);
CHECK(m->message_id.is_valid());
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);
}
}
@ -15150,7 +15148,7 @@ void MessagesManager::remove_dialog_mention_notifications(Dialog *d) {
if (message_id != d->pinned_message_notification_message_id) {
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)) {
CHECK(is_from_mention_notification_group(d, m));
CHECK(is_from_mention_notification_group(m));
removed_notification_ids_set.insert(m->notification_id);
}
}
@ -15846,7 +15844,7 @@ void MessagesManager::remove_message_notification_id(Dialog *d, Message *m, bool
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);
if (!group_info.group_id.is_valid()) {
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)) {
while (*it != nullptr) {
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) {
bool is_fixed = set_dialog_last_notification(d->dialog_id, group_info, m->date, m->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();
if (m->via_bot_user_id.is_valid() || m->hide_via_bot) {
// via bot message
if (!can_have_input_media(td_, m->content.get())) {
if (!can_have_input_media(td_, m->content.get(), false)) {
return false;
}
@ -27737,10 +27735,16 @@ class MessagesManager::ForwardMessagesLogEvent {
DialogId from_dialog_id;
vector<MessageId> message_ids;
vector<Message *> messages_in;
bool drop_author;
bool drop_media_captions;
vector<unique_ptr<Message>> messages_out;
template <class StorerT>
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(from_dialog_id, storer);
td::store(message_ids, storer);
@ -27749,6 +27753,12 @@ class MessagesManager::ForwardMessagesLogEvent {
template <class ParserT>
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(from_dialog_id, 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,
const vector<Message *> &messages,
const vector<MessageId> &message_ids) {
ForwardMessagesLogEvent log_event{to_dialog_id, from_dialog_id, message_ids, messages, Auto()};
const vector<MessageId> &message_ids, bool drop_author,
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,
get_log_event_storer(log_event));
}
void MessagesManager::do_forward_messages(DialogId to_dialog_id, DialogId from_dialog_id,
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());
if (messages.empty()) {
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) {
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]);
@ -27801,6 +27814,12 @@ void MessagesManager::do_forward_messages(DialogId to_dialog_id, DialogId from_d
if (messages[0]->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 =
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,
int64 media_album_id) const {
int64 media_album_id, bool drop_author) const {
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;
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->view_count = forwarded_message->view_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 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;
result.to_dialog = to_dialog;
result.from_dialog = from_dialog;
result.message_send_options = message_send_options;
auto &copied_messages = result.copied_messages;
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_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 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)) {
LOG(INFO) << "Forward of " << message_id << " is restricted";
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 reply_to_message_id = copy_options[i].reply_to_message_id;
auto reply_markup = std::move(copy_options[i].reply_markup);
unique_ptr<MessageContent> content =
dup_message_content(td_, to_dialog_id, forwarded_message->content.get(), type, std::move(copy_options[i]));
if (content == nullptr) {
LOG(INFO) << "Can't forward " << message_id;
LOG(INFO) << "Can't forward content of " << message_id;
continue;
}
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()) {
LOG(INFO) << "Can't forward " << message_id << ": " << can_send_status.message();
continue;
@ -28050,7 +28086,7 @@ Result<MessagesManager::ForwardedMessages> MessagesManager::get_forwarded_messag
}
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_media_album_id.second++;
if (new_media_album_id.second == 2) { // have at least 2 messages in the new album
@ -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,
std::move(reply_markup), forwarded_message->media_album_id,
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 &copied_messages = forwarded_messages_info.copied_messages;
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<Message *> forwarded_messages;
@ -28134,7 +28172,8 @@ Result<td_api::object_ptr<td_api::messages>> MessagesManager::forward_messages(
CHECK(forwarded_message != nullptr);
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()) &&
!forward_info->message_id.is_valid() && !forward_info->sender_dialog_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(),
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->real_forward_from_dialog_id = from_dialog_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()) {
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) {
@ -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) {
CHECK(d != 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,
@ -29107,13 +29148,13 @@ MessagesManager::MessageNotificationGroup MessagesManager::get_message_notificat
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;
}
bool MessagesManager::is_message_notification_active(const Dialog *d, const Message *m) {
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() &&
m->message_id > d->mention_notification_group.max_removed_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;
}
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
<< " from another group";
continue;
@ -29502,7 +29543,7 @@ void MessagesManager::on_get_message_notifications_from_database(DialogId dialog
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
<< " from another category";
continue;
@ -29569,7 +29610,7 @@ void MessagesManager::remove_message_notification(DialogId dialog_id, Notificati
CHECK(m != nullptr);
CHECK(m->notification_id == notification_id);
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);
}
return;
@ -29632,8 +29673,8 @@ void MessagesManager::do_remove_message_notification(DialogId dialog_id, bool fr
CHECK(d != nullptr);
auto m = on_get_message_from_database(d, result[0], false, "do_remove_message_notification");
if (m != nullptr && m->notification_id == notification_id &&
is_from_mention_notification_group(d, m) == from_mentions && is_message_notification_active(d, m)) {
if (m != nullptr && m->notification_id == notification_id && is_from_mention_notification_group(m) == from_mentions &&
is_message_notification_active(d, m)) {
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;
}
if (is_from_mention_notification_group(d, m)) {
if (is_from_mention_notification_group(m)) {
return true;
}
@ -29830,7 +29871,7 @@ bool MessagesManager::add_new_message_notification(Dialog *d, Message *m, bool f
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_active =
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;
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
auto sender_dialog_id = get_message_sender(m);
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);
} else {
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) {
auto notification_id = message->notification_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()) {
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;
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;
CHECK(!being_added_new_dialog_id_.is_valid());
being_added_new_dialog_id_ = dialog_id;
loaded_dialogs_.erase(dialog_id);
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);
being_added_new_dialog_id_ = DialogId();
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,
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);
counter_message.first--;
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));
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");
}
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;
}
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);
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,
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,
const Message *forwarded_message) const;
void fix_forwarded_message(Message *m, DialogId to_dialog_id, const Message *forwarded_message,
int64 media_album_id) const;
void fix_forwarded_message(Message *m, DialogId to_dialog_id, const Message *forwarded_message, int64 media_album_id,
bool drop_author) const;
struct ForwardedMessages {
struct CopiedMessage {
@ -1966,6 +1967,8 @@ class MessagesManager final : public Actor {
size_t index;
};
vector<ForwardedMessageContent> forwarded_message_contents;
bool drop_author = false;
bool drop_media_captions = false;
Dialog *from_dialog;
Dialog *to_dialog;
@ -2368,7 +2371,7 @@ class MessagesManager final : public Actor {
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);
@ -3251,8 +3254,8 @@ class MessagesManager final : public Actor {
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,
const vector<Message *> &messages,
const vector<MessageId> &message_ids);
const vector<Message *> &messages, 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);
@ -3678,6 +3681,7 @@ class MessagesManager final : public Actor {
DialogId being_added_dialog_id_;
DialogId being_added_by_new_message_dialog_id_;
DialogId being_added_new_dialog_id_;
DialogId debug_channel_difference_dialog_;

View File

@ -1472,10 +1472,6 @@ void NotificationSettingsManager::after_get_difference() {
if (!channels_notification_settings_.is_synchronized) {
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) {

View File

@ -35,6 +35,7 @@
#include "td/utils/Status.h"
#include <cmath>
#include <functional>
#include <limits>
namespace td {
@ -418,14 +419,14 @@ void OptionManager::set_option(const string &name, td_api::object_ptr<td_api::Op
if (name != option_name) {
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) {
G()->shared_config().set_option_empty(option_name);
} 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_;
if (int_value < min_value || int_value > max_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) {
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) {
G()->shared_config().set_option_empty(name);
} 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_;
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;
};
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) {
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) {
G()->shared_config().set_option_empty(name);
} 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_;
if (str_value.empty()) {
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 ||
static_cast<const td_api::optionValueBoolean *>(value.get())->value_;
td_->set_is_online(is_online);
if (!is_bot) {
send_closure(td_->state_manager_, &StateManager::on_online, is_online);
}
td_->set_is_online(is_online);
return promise.set_value(Unit());
}
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());
}
send_closure(G()->contacts_manager(), &ContactsManager::on_get_user, result.move_as_ok(), "process_check_code_result",
true, false);
true);
state_ = State::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_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() {
@ -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));
}
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) {
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) {
auto p = polls_.find(poll_id);
if (p == polls_.end()) {
return nullptr;
} else {
schedule_poll_unload(poll_id);
return p->second.get();
}
}
@ -310,15 +333,20 @@ bool PollManager::have_poll(PollId poll_id) const {
}
void PollManager::notify_on_poll_update(PollId poll_id) {
auto it = poll_messages_.find(poll_id);
if (it == poll_messages_.end()) {
return;
auto server_it = server_poll_messages_.find(poll_id);
if (server_it != server_poll_messages_.end()) {
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);
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);
}
}
}
string PollManager::get_poll_database_key(PollId poll_id) {
return PSTRING() << "poll" << poll_id.get();
@ -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) {
CHECK(have_poll(poll_id));
if (full_message_id.get_message_id().is_scheduled()) {
return;
}
if (!full_message_id.get_message_id().is_server()) {
if (full_message_id.get_message_id().is_scheduled() || !full_message_id.get_message_id().is_server()) {
bool is_inserted = other_poll_messages_[poll_id].insert(full_message_id).second;
LOG_CHECK(is_inserted) << source << ' ' << poll_id << ' ' << full_message_id;
unload_poll_timeout_.cancel_timeout(poll_id.get());
return;
}
LOG(INFO) << "Register " << poll_id << " from " << full_message_id << " from " << source;
bool is_inserted = poll_messages_[poll_id].insert(full_message_id).second;
LOG_CHECK(is_inserted) << source << " " << poll_id << " " << full_message_id;
bool is_inserted = server_poll_messages_[poll_id].insert(full_message_id).second;
LOG_CHECK(is_inserted) << source << ' ' << poll_id << ' ' << full_message_id;
auto poll = get_poll(poll_id);
CHECK(poll != nullptr);
if (!td_->auth_manager_->is_bot() && !is_local_poll_id(poll_id) &&
!(poll->is_closed && poll->is_updated_after_close)) {
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) {
CHECK(have_poll(poll_id));
if (full_message_id.get_message_id().is_scheduled()) {
return;
if (full_message_id.get_message_id().is_scheduled() || !full_message_id.get_message_id().is_server()) {
auto &message_ids = other_poll_messages_[poll_id];
auto is_deleted = message_ids.erase(full_message_id) > 0;
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);
}
if (!full_message_id.get_message_id().is_server()) {
return;
}
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;
LOG_CHECK(is_deleted) << source << " " << poll_id << " " << full_message_id;
LOG_CHECK(is_deleted) << source << ' ' << poll_id << ' ' << full_message_id;
if (message_ids.empty()) {
poll_messages_.erase(poll_id);
server_poll_messages_.erase(poll_id);
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);
return;
}
unload_poll_timeout_.cancel_timeout(poll_id.get());
auto &pending_answer = pending_answers_[poll_id];
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;
}
unload_poll_timeout_.cancel_timeout(poll_id.get());
auto query_promise =
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 {
@ -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));
}
unload_poll_timeout_.cancel_timeout(poll_id.get());
bool is_inserted = being_closed_polls_.insert(poll_id).second;
CHECK(is_inserted);
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));
auto poll = get_poll(poll_id);
CHECK(poll != nullptr);
if (poll->is_closed && poll->is_updated_after_close) {
if (poll == nullptr || (poll->is_closed && poll->is_updated_after_close)) {
return;
}
if (pending_answers_.count(poll_id) > 0) {
@ -1177,8 +1242,8 @@ void PollManager::on_update_poll_timeout(PollId poll_id) {
return;
}
auto it = poll_messages_.find(poll_id);
if (it == poll_messages_.end()) {
auto it = server_poll_messages_.find(poll_id);
if (it == server_poll_messages_.end()) {
return;
}
@ -1198,8 +1263,7 @@ void PollManager::on_close_poll_timeout(PollId poll_id) {
CHECK(!is_local_poll_id(poll_id));
auto poll = get_poll_editable(poll_id);
CHECK(poll != nullptr);
if (poll->is_closed || poll->close_date == 0) {
if (poll == nullptr || poll->is_closed || poll->close_date == 0) {
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,
Result<tl_object_ptr<telegram_api::Updates>> result) {
auto poll = get_poll(poll_id);
CHECK(poll != nullptr);
if (poll == nullptr) {
return;
}
if (result.is_error()) {
if (!(poll->is_closed && poll->is_updated_after_close) && !G()->close_flag() && !td_->auth_manager_->is_bot()) {
auto timeout = get_polling_timeout();
@ -1250,7 +1338,7 @@ void PollManager::on_online() {
return;
}
for (auto &it : poll_messages_) {
for (auto &it : server_poll_messages_) {
auto poll_id = it.first;
if (update_poll_timeout_.has_timeout(poll_id.get())) {
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))) {
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;
}

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 UNLOAD_POLL_DELAY = 600; // some reasonable value
class SetPollAnswerLogEvent;
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_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 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);
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);
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_unload_poll_timeout(PollId poll_id);
void on_online();
Poll *get_poll_force(PollId poll_id);
@ -206,12 +217,14 @@ class PollManager final : public Actor {
MultiTimeout update_poll_timeout_{"UpdatePollTimeout"};
MultiTimeout close_poll_timeout_{"ClosePollTimeout"};
MultiTimeout unload_poll_timeout_{"UnloadPollTimeout"};
Td *td_;
ActorShared<> parent_;
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 {
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
#include "td/telegram/PhotoSize.h"
#include "td/telegram/secret_api.h"
#include "td/telegram/telegram_api.h"
#include "td/utils/buffer.h"
#include "td/utils/common.h"
namespace td {
class FileView;
struct SecretInputMedia {
tl_object_ptr<telegram_api::InputEncryptedFile> input_file_;
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)) {
}
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 {
return decrypted_media_ == nullptr;
}

View File

@ -1462,6 +1462,10 @@ void StickersManager::reload_special_sticker_set_by_type(SpecialStickerSetType t
if (G()->close_flag()) {
return;
}
if (disable_animated_emojis_ &&
(type == SpecialStickerSetType::animated_emoji() || type == SpecialStickerSetType::animated_emoji_click())) {
return;
}
auto &sticker_set = add_special_sticker_set(type);
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_);
reset_to_empty(pending_get_animated_emoji_click_stickers_);
for (auto &pending_request : pending_get_requests) {
choose_animated_emoji_click_sticker(sticker_set, pending_request.message_text_, pending_request.full_message_id_,
pending_request.start_time_, std::move(pending_request.promise_));
choose_animated_emoji_click_sticker(sticker_set, std::move(pending_request.message_text_),
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_);
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 {};
}
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);
if (it == sticker_set->emoji_stickers_map_.end()) {
return {};
@ -2748,13 +2753,13 @@ SecretInputMedia StickersManager::get_secret_input_media(FileId sticker_file_id,
}
if (file_view.is_encrypted_secret()) {
auto &encryption_key = file_view.encryption_key();
return SecretInputMedia{std::move(input_file),
make_tl_object<secret_api::decryptedMessageMediaDocument>(
std::move(thumbnail), sticker->s_thumbnail.dimensions.width,
sticker->s_thumbnail.dimensions.height, get_sticker_format_mime_type(sticker->format),
narrow_cast<int32>(file_view.size()), BufferSlice(encryption_key.key_slice()),
BufferSlice(encryption_key.iv_slice()), std::move(attributes), "")};
return {std::move(input_file),
std::move(thumbnail),
sticker->s_thumbnail.dimensions,
get_sticker_format_mime_type(sticker->format),
file_view,
std::move(attributes),
string()};
} else {
CHECK(!file_view.is_encrypted());
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->sticker_emojis_map_.clear();
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()) {
LOG(ERROR) << "Receive empty emoji in " << set_id << "/" << s->short_name << " from " << source;
continue;
@ -4640,11 +4645,11 @@ vector<FileId> StickersManager::get_animated_emoji_click_stickers(const StickerS
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,
Promise<td_api::object_ptr<td_api::sticker>> &&promise) {
CHECK(sticker_set->was_loaded);
message_text = remove_emoji_modifiers(message_text);
remove_emoji_modifiers_in_place(message_text);
if (message_text.empty()) {
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) {
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) {
@ -4798,7 +4803,7 @@ void StickersManager::flush_sent_animated_emoji_clicks() {
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();
for (const auto &click : sent_animated_emoji_clicks_) {
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;
}
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_) {
return Status::OK();
}
@ -4871,7 +4876,7 @@ Status StickersManager::on_animated_emoji_message_clicked(Slice emoji, FullMessa
load_special_sticker_set(special_sticker_set);
PendingOnAnimatedEmojiClicked pending_request;
pending_request.emoji_ = emoji.str();
pending_request.emoji_ = std::move(emoji);
pending_request.full_message_id_ = full_message_id;
pending_request.clicks_ = std::move(clicks);
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;
}
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 {
if (td_->auth_manager_->is_bot()) {
return;

View File

@ -89,9 +89,9 @@ class StickersManager final : public Actor {
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;
@ -135,6 +135,10 @@ class StickersManager final : public Actor {
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_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 after_get_difference();
void get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const;
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;
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,
Promise<td_api::object_ptr<td_api::sticker>> &&promise);
@ -704,8 +706,6 @@ class StickersManager final : public Actor {
void load_reactions();
void reload_reactions();
void update_active_reactions();
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 reload_special_sticker_set_by_type(SpecialStickerSetType type, bool is_recursive = false);
void reload_special_sticker_set(SpecialStickerSet &sticker_set, int32 hash);
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;
parse(emojis, parser);
for (auto &emoji : emojis) {
auto cleaned_emoji = remove_emoji_modifiers(emoji).str();
auto cleaned_emoji = remove_emoji_modifiers(emoji);
if (!cleaned_emoji.empty()) {
auto &sticker_ids = sticker_set->emoji_stickers_map_[cleaned_emoji];
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<> {
string name_;
@ -3687,9 +3671,6 @@ void Td::close_impl(bool destroy_flag) {
class Td::DownloadFileCallback final : public FileManager::DownloadCallback {
public:
void on_progress(FileId file_id) final {
}
void on_download_ok(FileId file_id) final {
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 {
public:
void on_progress(FileId file_id) 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
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) {
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) {

View File

@ -38,10 +38,12 @@
#include "td/telegram/PollId.h"
#include "td/telegram/PollManager.h"
#include "td/telegram/PrivacyManager.h"
#include "td/telegram/PublicDialogType.h"
#include "td/telegram/ScheduledServerMessageId.h"
#include "td/telegram/SecretChatId.h"
#include "td/telegram/SecretChatsManager.h"
#include "td/telegram/ServerMessageId.h"
#include "td/telegram/SpecialStickerSetType.h"
#include "td/telegram/StateManager.h"
#include "td/telegram/StickerSetId.h"
#include "td/telegram/StickersManager.h"
@ -181,6 +183,26 @@ void UpdatesManager::tear_down() {
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() {
ref_cnt_--;
if (ref_cnt_ == 0) {
@ -1557,15 +1579,65 @@ void UpdatesManager::after_get_difference() {
<< 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_->inline_queries_manager_->after_get_difference();
td_->messages_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(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,

View File

@ -221,12 +221,17 @@ class UpdatesManager final : public Actor {
int32 retry_time_ = 1;
Timeout retry_timeout_;
double next_data_reload_time_ = 0.0;
Timeout data_reload_timeout_;
bool running_get_difference_ = false;
int32 last_get_difference_pts_ = 0;
int32 last_get_difference_qts_ = 0;
int32 min_postponed_update_pts_ = 0;
int32 min_postponed_update_qts_ = 0;
void start_up() final;
void tear_down() final;
void hangup_shared() final;
@ -331,6 +336,12 @@ class UpdatesManager final : public Actor {
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 check_pts_update_dialog_id(DialogId dialog_id);

View File

@ -50,6 +50,7 @@ enum class Version : int32 {
AddInviteLinksRequiringApproval,
AddKeyboardButtonFlags, // 35
AddAudioFlags,
UseServerForwardAsCopy,
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);
CHECK(video_note != nullptr);
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() || encryption_key.empty()) {
if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty()) {
return SecretInputMedia{};
}
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>(
secret_api::documentAttributeVideo66::ROUND_MESSAGE_MASK, true, video_note->duration,
video_note->dimensions.width, video_note->dimensions.height));
return SecretInputMedia{
std::move(input_file),
make_tl_object<secret_api::decryptedMessageMediaDocument>(
std::move(thumbnail), video_note->thumbnail.dimensions.width, video_note->thumbnail.dimensions.height,
"video/mp4", narrow_cast<int32>(file_view.size()), BufferSlice(encryption_key.key_slice()),
BufferSlice(encryption_key.iv_slice()), std::move(attributes), "")};
return {std::move(input_file),
std::move(thumbnail),
video_note->thumbnail.dimensions,
"video/mp4",
file_view,
std::move(attributes),
string()};
}
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);
CHECK(video != nullptr);
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() || encryption_key.empty()) {
if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty()) {
return SecretInputMedia{};
}
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()) {
return {};
}
return SecretInputMedia{
std::move(input_file),
make_tl_object<secret_api::decryptedMessageMediaVideo>(
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()),
BufferSlice(encryption_key.key_slice()), BufferSlice(encryption_key.iv_slice()), caption)};
vector<tl_object_ptr<secret_api::DocumentAttribute>> attributes;
attributes.emplace_back(make_tl_object<secret_api::documentAttributeVideo>(video->duration, video->dimensions.width,
video->dimensions.height));
return {std::move(input_file),
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(

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);
CHECK(voice_note != nullptr);
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() || encryption_key.empty()) {
if (!file_view.is_encrypted_secret() || file_view.encryption_key().empty()) {
return SecretInputMedia{};
}
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>(
secret_api::documentAttributeAudio::VOICE_MASK | secret_api::documentAttributeAudio::WAVEFORM_MASK,
false /*ignored*/, voice_note->duration, "", "", BufferSlice(voice_note->waveform)));
return SecretInputMedia{std::move(input_file),
make_tl_object<secret_api::decryptedMessageMediaDocument>(
BufferSlice(), 0, 0, voice_note->mime_type, narrow_cast<int32>(file_view.size()),
BufferSlice(encryption_key.key_slice()), BufferSlice(encryption_key.iv_slice()),
std::move(attributes), caption)};
return {std::move(input_file), BufferSlice(), Dimensions(), voice_note->mime_type, file_view,
std::move(attributes), caption};
}
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;
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
// explicit upload request with the same file_id.
// 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/ConcurrentHashMap.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/EpochBasedMemoryReclamation.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/filesystem.cpp

View File

@ -243,7 +243,13 @@ Slice remove_fitzpatrick_modifier(Slice 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 */,
u8"\u200D\u2640" /* zero width joiner + female 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"\U0001F3FE" /* emoji modifier fitzpatrick type-5 */,
u8"\U0001F3FF" /* emoji modifier fitzpatrick type-6 */};
bool found = true;
while (found) {
found = false;
size_t j = 0;
for (size_t i = 0; i < emoji.size();) {
bool is_found = false;
for (auto &modifier : modifiers) {
if (ends_with(emoji, modifier) && emoji.size() > modifier.size()) {
emoji.remove_suffix(modifier.size());
found = true;
auto length = modifier.size();
if (i + length <= emoji.size() && Slice(&emoji[i], length) == modifier) {
// skip modifier
i += length;
is_found = true;
break;
}
}
if (!is_found) {
emoji[j++] = emoji[i++];
}
return emoji;
}
void remove_emoji_modifiers_in_place(string &emoji) {
emoji.resize(remove_emoji_modifiers(emoji).size());
emoji.resize(j);
}
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
Slice remove_fitzpatrick_modifier(Slice emoji);
// removes all emoji modifiers from the end of the string
Slice remove_emoji_modifiers(Slice emoji);
// removes all emoji modifiers from the string
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);
// 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(
"012345678901234567890123456789012345678901234567890123456789adsasdasdsaa.01234567890123456789asdasdasdasd",
"012345678901234567890123456789012345678901234567890123456789.01234567890123456789");
"012345678901234567890123456789012345678901234567890123456789adsa.0123456789012345");
test_clean_filename(
"01234567890123456789012345678901234567890123456789<>*?: <>*?:0123456789adsasdasdsaa. "
"01234567890123456789012345678901234567890123456789adsa<>*?: <>*?:0123456789adsasdasdsaa. "
"0123456789`<><<>><><>0123456789asdasdasdasd",
"01234567890123456789012345678901234567890123456789.0123456789");
"01234567890123456789012345678901234567890123456789adsa.0123456789");
test_clean_filename(
"01234567890123456789012345678901234567890123456789<>*?: <>*?:0123456789adsasdasdsaa. "
"0123456789`<><><>0123456789asdasdasdasd",
"01234567890123456789012345678901234567890123456789.0123456789 012");
"012345678901234567890123456789012345678901234567890123<>*?: <>*?:0123456789adsasdasdsaa. "
"0123456789`<>0123456789asdasdasdasd",
"012345678901234567890123456789012345678901234567890123.0123456789 012");
test_clean_filename("C:/document.tar.gz", "document.tar.gz");
test_clean_filename("test....", "test");
test_clean_filename("....test", "test");
test_clean_filename("test.exe....", "test.exe"); // extension has changed
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("കറുപ്പ്.txt", "കറപപ.txt");
}

View File

@ -11,7 +11,6 @@
#include "td/utils/bits.h"
#include "td/utils/CancellationToken.h"
#include "td/utils/common.h"
#include "td/utils/emoji.h"
#include "td/utils/ExitGuard.h"
#include "td/utils/Hash.h"
#include "td/utils/HashMap.h"
@ -1215,27 +1214,6 @@ TEST(Misc, uname) {
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) {
td::int32 x = 1;
ASSERT_EQ(td::base64_encode(td::serialize(x)), td::base64_encode(td::string("\x01\x00\x00\x00", 4)));