diff --git a/td/telegram/BotMenuButton.cpp b/td/telegram/BotMenuButton.cpp index 4b6cfc341..4676f856d 100644 --- a/td/telegram/BotMenuButton.cpp +++ b/td/telegram/BotMenuButton.cpp @@ -143,8 +143,7 @@ void set_menu_button(Td *td, UserId user_id, td_api::object_ptrurl_, true, !G()->is_test_dc()); if (r_url.is_error()) { - return promise.set_error(Status::Error(400, PSLICE() << "Menu button web app URL '" << menu_button->url_ - << "' is invalid: " << r_url.error().message())); + return promise.set_error(Status::Error(400, PSLICE() << "Menu button Web App " << r_url.error().message())); } input_bot_menu_button = telegram_api::make_object(menu_button->text_, r_url.ok()); } diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 948bba9b9..b1e675c0d 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -15808,6 +15808,10 @@ void ContactsManager::on_update_dialog_administrators(DialogId dialog_id, vector void ContactsManager::reload_dialog_administrators(DialogId dialog_id, const vector &dialog_administrators, Promise> &&promise) { + auto dialog_type = dialog_id.get_type(); + if (dialog_type == DialogType::Chat && !get_chat_permissions(dialog_id.get_chat_id()).is_member()) { + return promise.set_value(td_api::object_ptr()); + } auto query_promise = PromiseCreator::lambda( [actor_id = actor_id(this), dialog_id, promise = std::move(promise)](Result &&result) mutable { if (promise) { @@ -15818,7 +15822,7 @@ void ContactsManager::reload_dialog_administrators(DialogId dialog_id, } } }); - switch (dialog_id.get_type()) { + switch (dialog_type) { case DialogType::Chat: load_chat_full(dialog_id.get_chat_id(), false, std::move(query_promise), "reload_dialog_administrators"); break; diff --git a/td/telegram/GroupCallManager.cpp b/td/telegram/GroupCallManager.cpp index 91d88d888..ceaa92d55 100644 --- a/td/telegram/GroupCallManager.cpp +++ b/td/telegram/GroupCallManager.cpp @@ -4675,14 +4675,15 @@ bool GroupCallManager::set_group_call_participant_count(GroupCall *group_call, i } LOG(DEBUG) << "Set " << group_call->group_call_id << " participant count to " << count << " from " << source; + auto input_group_call_id = get_input_group_call_id(group_call->group_call_id).ok(); if (count < 0) { LOG(ERROR) << "Participant count became negative in " << group_call->group_call_id << " in " << group_call->dialog_id << " from " << source; count = 0; + reload_group_call(input_group_call_id, Auto()); } bool result = false; - auto input_group_call_id = get_input_group_call_id(group_call->group_call_id).ok(); if (need_group_call_participants(input_group_call_id, group_call)) { auto known_participant_count = static_cast(add_group_call_participants(input_group_call_id)->participants.size()); @@ -4738,6 +4739,8 @@ bool GroupCallManager::set_group_call_unmuted_video_count(GroupCall *group_call, LOG(ERROR) << "Video participant count became negative in " << group_call->group_call_id << " in " << group_call->dialog_id << " from " << source; count = 0; + auto input_group_call_id = get_input_group_call_id(group_call->group_call_id).ok(); + reload_group_call(input_group_call_id, Auto()); } if (group_call->unmuted_video_count == count) { diff --git a/td/telegram/LinkManager.cpp b/td/telegram/LinkManager.cpp index e16acd39d..ca07fc961 100644 --- a/td/telegram/LinkManager.cpp +++ b/td/telegram/LinkManager.cpp @@ -708,7 +708,28 @@ static bool tolower_begins_with(Slice str, Slice prefix) { return true; } -Result LinkManager::check_link(Slice link, bool http_only, bool https_only) { +Result LinkManager::check_link(CSlice link, bool http_only, bool https_only) { + auto result = check_link_impl(link, http_only, https_only); + if (result.is_ok()) { + return std::move(result); + } + auto error = result.move_as_error(); + if (check_utf8(link)) { + return Status::Error(400, PSLICE() << "URL '" << link << "' is invalid: " << error.message()); + } else { + return Status::Error(400, PSLICE() << "URL is invalid: " << error.message()); + } +} + +string LinkManager::get_checked_link(Slice link, bool http_only, bool https_only) { + auto result = check_link_impl(link, http_only, https_only); + if (result.is_ok()) { + return result.move_as_ok(); + } + return string(); +} + +Result LinkManager::check_link_impl(Slice link, bool http_only, bool https_only) { bool is_tg = false; bool is_ton = false; if (tolower_begins_with(link, "tg:")) { diff --git a/td/telegram/LinkManager.h b/td/telegram/LinkManager.h index 810129e06..9fcf91e16 100644 --- a/td/telegram/LinkManager.h +++ b/td/telegram/LinkManager.h @@ -47,7 +47,10 @@ class LinkManager final : public Actor { }; // checks whether the link is a valid tg, ton or HTTP(S) URL and returns it in a canonical form - static Result check_link(Slice link, bool http_only = false, bool https_only = false); + static Result check_link(CSlice link, bool http_only = false, bool https_only = false); + + // same as check_link, but returns an empty string instead of an error + static string get_checked_link(Slice link, bool http_only = false, bool https_only = false); // checks whether the link is a supported tg or t.me link and parses it static unique_ptr parse_internal_link(Slice link); @@ -128,6 +131,8 @@ class LinkManager final : public Actor { static unique_ptr get_internal_link_message_draft(Slice url, Slice text); + static Result check_link_impl(Slice link, bool http_only, bool https_only); + Td *td_; ActorShared<> parent_; diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index 4db0e0deb..b3e5d74c7 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -1723,7 +1723,7 @@ static Result create_input_message_content( td->animations_manager_->create_animation( file_id, string(), thumbnail, AnimationSize(), has_stickers, std::move(sticker_file_ids), std::move(file_name), std::move(mime_type), input_animation->duration_, - get_dimensions(input_animation->width_, input_animation->height_, "inputMessageAnimation"), false); + get_dimensions(input_animation->width_, input_animation->height_, nullptr), false); content = make_unique(file_id, std::move(caption)); break; @@ -1792,7 +1792,7 @@ static Result create_input_message_content( PhotoSize s; s.type = type; - s.dimensions = get_dimensions(input_photo->width_, input_photo->height_, "inputMessagePhoto"); + s.dimensions = get_dimensions(input_photo->width_, input_photo->height_, nullptr); s.size = static_cast(file_view.size()); s.file_id = file_id; @@ -1815,10 +1815,9 @@ static Result create_input_message_content( emoji = std::move(input_sticker->emoji_); - td->stickers_manager_->create_sticker( - file_id, string(), thumbnail, - get_dimensions(input_sticker->width_, input_sticker->height_, "inputMessageSticker"), nullptr, - StickerFormat::Unknown, nullptr); + td->stickers_manager_->create_sticker(file_id, string(), thumbnail, + get_dimensions(input_sticker->width_, input_sticker->height_, nullptr), + nullptr, StickerFormat::Unknown, nullptr); content = make_unique(file_id); break; @@ -1829,11 +1828,10 @@ static Result create_input_message_content( ttl = input_video->ttl_; bool has_stickers = !sticker_file_ids.empty(); - td->videos_manager_->create_video(file_id, string(), thumbnail, AnimationSize(), has_stickers, - std::move(sticker_file_ids), std::move(file_name), std::move(mime_type), - input_video->duration_, - get_dimensions(input_video->width_, input_video->height_, "inputMessageVideo"), - input_video->supports_streaming_, false); + td->videos_manager_->create_video( + file_id, string(), thumbnail, AnimationSize(), has_stickers, std::move(sticker_file_ids), + std::move(file_name), std::move(mime_type), input_video->duration_, + get_dimensions(input_video->width_, input_video->height_, nullptr), input_video->supports_streaming_, false); content = make_unique(file_id, std::move(caption)); break; @@ -1847,7 +1845,7 @@ static Result create_input_message_content( } td->video_notes_manager_->create_video_note(file_id, string(), thumbnail, input_video_note->duration_, - get_dimensions(length, length, "inputMessageVideoNote"), false); + get_dimensions(length, length, nullptr), false); content = make_unique(file_id, false); break; @@ -2083,7 +2081,7 @@ Result get_input_message_content( LOG(WARNING) << "Ignore thumbnail file: " << r_thumbnail_file_id.error().message(); } else { thumbnail.type = 't'; - thumbnail.dimensions = get_dimensions(input_thumbnail->width_, input_thumbnail->height_, "inputThumbnail"); + thumbnail.dimensions = get_dimensions(input_thumbnail->width_, input_thumbnail->height_, nullptr); thumbnail.file_id = r_thumbnail_file_id.ok(); CHECK(thumbnail.file_id.is_valid()); @@ -4334,8 +4332,8 @@ unique_ptr get_message_content(Td *td, FormattedText message, } case telegram_api::messageMediaPoll::ID: { auto media_poll = move_tl_object_as(media); - auto poll_id = - td->poll_manager_->on_get_poll(PollId(), std::move(media_poll->poll_), std::move(media_poll->results_)); + auto poll_id = td->poll_manager_->on_get_poll(PollId(), std::move(media_poll->poll_), + std::move(media_poll->results_), "messageMediaPoll"); if (!poll_id.is_valid()) { break; } diff --git a/td/telegram/MessageEntity.cpp b/td/telegram/MessageEntity.cpp index db4c2029f..e0561b8e7 100644 --- a/td/telegram/MessageEntity.cpp +++ b/td/telegram/MessageEntity.cpp @@ -1876,9 +1876,9 @@ Result> parse_markdown(string &text) { if (user_id.is_valid()) { entities.emplace_back(entity_offset, entity_length, user_id); } else { - auto r_url = LinkManager::check_link(url); - if (r_url.is_ok()) { - entities.emplace_back(MessageEntity::Type::TextUrl, entity_offset, entity_length, r_url.move_as_ok()); + url = LinkManager::get_checked_link(url); + if (!url.empty()) { + entities.emplace_back(MessageEntity::Type::TextUrl, entity_offset, entity_length, std::move(url)); } } break; @@ -2092,11 +2092,11 @@ static Result> do_parse_markdown_v2(CSlice text, string &r } user_id = LinkManager::get_link_user_id(url); if (!user_id.is_valid()) { - auto r_url = LinkManager::check_link(url); - if (r_url.is_error()) { + url = LinkManager::get_checked_link(url); + if (url.empty()) { skip_entity = true; } else { - argument = r_url.move_as_ok(); + argument = std::move(url); } } break; @@ -2169,7 +2169,7 @@ static vector find_text_url_entities_v3(Slice text) { if (url_end < size) { Slice url = text.substr(url_begin + 1, url_end - url_begin - 1); - if (LinkManager::check_link(url).is_ok()) { + if (!LinkManager::get_checked_link(url).empty()) { result.push_back(text.substr(text_begin, text_end - text_begin + 1)); result.push_back(text.substr(url_begin, url_end - url_begin + 1)); } @@ -2241,7 +2241,7 @@ static FormattedText parse_text_url_entities_v3(Slice text, const vector> do_parse_html(CSlice text, string &result) if (user_id.is_valid()) { entities.emplace_back(entity_offset, entity_length, user_id); } else { - auto r_url = LinkManager::check_link(url); - if (r_url.is_ok()) { - entities.emplace_back(MessageEntity::Type::TextUrl, entity_offset, entity_length, r_url.move_as_ok()); + url = LinkManager::get_checked_link(url); + if (!url.empty()) { + entities.emplace_back(MessageEntity::Type::TextUrl, entity_offset, entity_length, std::move(url)); } } } else if (tag_name == "pre") { @@ -3284,7 +3284,7 @@ Result> get_message_entities(const ContactsManager *contac } auto r_url = LinkManager::check_link(entity->url_); if (r_url.is_error()) { - return Status::Error(400, PSTRING() << "Wrong URL entity specified: " << r_url.error().message()); + return Status::Error(400, PSTRING() << "Entity " << r_url.error().message()); } entities.emplace_back(MessageEntity::Type::TextUrl, offset, length, r_url.move_as_ok()); break; @@ -3418,8 +3418,7 @@ vector get_message_entities(const ContactsManager *contacts_manag auto entity = static_cast(server_entity.get()); auto r_url = LinkManager::check_link(entity->url_); if (r_url.is_error()) { - LOG(ERROR) << "Wrong URL entity: \"" << entity->url_ << "\": " << r_url.error().message() << " from " - << source; + LOG(ERROR) << "Entity " << r_url.error().message() << " from " << source; continue; } entities.emplace_back(MessageEntity::Type::TextUrl, entity->offset_, entity->length_, r_url.move_as_ok()); @@ -3540,7 +3539,7 @@ vector get_message_entities(vectorurl_); if (r_url.is_error()) { - LOG(WARNING) << "Wrong URL entity: \"" << entity->url_ << "\": " << r_url.error().message(); + LOG(WARNING) << "Entity " << r_url.error().message(); continue; } entities.emplace_back(MessageEntity::Type::TextUrl, entity->offset_, entity->length_, r_url.move_as_ok()); diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index f882a4ef3..6ebd00ef7 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -871,6 +871,9 @@ class SearchPublicDialogsQuery final : public Td::ResultHandler { void on_error(Status status) final { if (!G()->is_expected_error(status)) { + if (status.message() == "QUERY_TOO_SHORT") { + return td_->messages_manager_->on_get_public_dialogs_search_result(query_, {}, {}); + } LOG(ERROR) << "Receive error for SearchPublicDialogsQuery: " << status; } td_->messages_manager_->on_failed_public_dialogs_search(query_, std::move(status)); @@ -9683,7 +9686,7 @@ void MessagesManager::on_get_history(DialogId dialog_id, MessageId from_message_ // new server messages were added to the dialog since the request was sent, but weren't received // they should have been received, so we must repeat the request to get them if (from_the_end) { - get_history_from_the_end_impl(d, false, false, std::move(promise)); + get_history_from_the_end_impl(d, false, false, std::move(promise), "on_get_history"); } else { get_history_impl(d, from_message_id, offset, limit, false, false, std::move(promise)); } @@ -9786,14 +9789,15 @@ void MessagesManager::on_get_history(DialogId dialog_id, MessageId from_message_ } for (auto &message : messages) { - if (!have_next && from_the_end && get_message_id(message, false) < d->last_message_id) { + auto expected_message_id = get_message_id(message, false); + if (!have_next && from_the_end && expected_message_id < d->last_message_id) { // last message in the dialog should be attached to the next message if there is some have_next = true; } auto message_dialog_id = get_message_dialog_id(message); if (message_dialog_id != dialog_id) { - LOG(ERROR) << "Receive " << get_message_id(message, false) << " in wrong " << message_dialog_id << " instead of " + LOG(ERROR) << "Receive " << expected_message_id << " in wrong " << message_dialog_id << " instead of " << dialog_id << ": " << oneline(to_string(message)); continue; } @@ -9802,6 +9806,7 @@ void MessagesManager::on_get_history(DialogId dialog_id, MessageId from_message_ on_get_message(std::move(message), false, is_channel_message, false, false, have_next, "get history"); auto message_id = full_message_id.get_message_id(); if (message_id.is_valid()) { + CHECK(message_id == expected_message_id); if (!last_added_message_id.is_valid()) { last_added_message_id = message_id; } @@ -12666,7 +12671,7 @@ void MessagesManager::set_dialog_max_unavailable_message_id(DialogId dialog_id, } if (max_unavailable_message_id.is_valid() && max_unavailable_message_id.is_yet_unsent()) { - LOG(ERROR) << "Tried to update " << dialog_id << " last read outbox message with " << max_unavailable_message_id + LOG(ERROR) << "Tried to update " << dialog_id << " max unavailable message with " << max_unavailable_message_id << " from " << source; return; } @@ -17373,7 +17378,9 @@ void MessagesManager::synchronize_dialog_filters() { vector MessagesManager::search_public_dialogs(const string &query, Promise &&promise) { LOG(INFO) << "Search public chats with query = \"" << query << '"'; - if (utf8_length(query) < MIN_SEARCH_PUBLIC_DIALOG_PREFIX_LEN) { + auto query_length = utf8_length(query); + if (query_length < MIN_SEARCH_PUBLIC_DIALOG_PREFIX_LEN || + (query_length == MIN_SEARCH_PUBLIC_DIALOG_PREFIX_LEN && query[0] == '@')) { string username = clean_username(query); if (username[0] == '@') { username = username.substr(1); @@ -23631,7 +23638,7 @@ void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId // new messages where added to the database since the request was sent // they should have been received from the database, so we must repeat the request to get them if (from_the_end) { - get_history_from_the_end_impl(d, true, only_local, std::move(promise)); + get_history_from_the_end_impl(d, true, only_local, std::move(promise), "on_get_history_from_database 20"); } else { get_history_impl(d, from_message_id, offset, limit, true, only_local, std::move(promise)); } @@ -23660,7 +23667,8 @@ void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId auto debug_first_database_message_id = d->first_database_message_id; auto debug_last_message_id = d->last_message_id; auto debug_last_new_message_id = d->last_new_message_id; - auto last_received_message_id = MessageId::max(); + auto first_received_message_id = MessageId::max(); + MessageId last_received_message_id; size_t pos = 0; for (auto &message_slice : messages) { if (!d->first_database_message_id.is_valid() && !d->have_full_history) { @@ -23675,13 +23683,16 @@ void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId } break; } - if (message->message_id >= last_received_message_id) { - LOG(ERROR) << "Receive " << message->message_id << " after " << last_received_message_id + if (message->message_id >= first_received_message_id) { + LOG(ERROR) << "Receive " << message->message_id << " after " << first_received_message_id << " from database in the history of " << dialog_id << " from " << from_message_id << " with offset " << offset << ", limit " << limit << ", from_the_end = " << from_the_end; break; } - last_received_message_id = message->message_id; + first_received_message_id = message->message_id; + if (!last_received_message_id.is_valid()) { + last_received_message_id = message->message_id; + } if (message->message_id < d->first_database_message_id) { if (d->have_full_history) { @@ -23718,10 +23729,11 @@ void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId } if (next_message != nullptr && !next_message->have_previous) { LOG_CHECK(m->message_id < next_message->message_id) - << m->message_id << ' ' << next_message->message_id << ' ' << last_received_message_id << ' ' << dialog_id - << ' ' << from_message_id << ' ' << offset << ' ' << limit << ' ' << from_the_end << ' ' << only_local - << ' ' << messages.size() << ' ' << debug_first_database_message_id << ' ' << last_added_message_id << ' ' - << added_new_message << ' ' << pos << ' ' << m << ' ' << next_message << ' ' << old_message << ' ' + << m->message_id << ' ' << next_message->message_id << ' ' << first_received_message_id << ' ' + << last_received_message_id << ' ' << dialog_id << ' ' << from_message_id << ' ' << offset << ' ' << limit + << ' ' << from_the_end << ' ' << only_local << ' ' << messages.size() << ' ' + << debug_first_database_message_id << ' ' << last_added_message_id << ' ' << added_new_message << ' ' << pos + << ' ' << m << ' ' << next_message << ' ' << old_message << ' ' << to_string(get_message_object(dialog_id, m, "on_get_history_from_database")) << to_string(get_message_object(dialog_id, next_message, "on_get_history_from_database")); LOG(INFO) << "Fix have_previous for " << next_message->message_id; @@ -23744,35 +23756,39 @@ void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId if (from_the_end && !last_added_message_id.is_valid() && d->first_database_message_id.is_valid() && !d->have_full_history) { - if (last_received_message_id <= d->first_database_message_id) { + if (first_received_message_id <= d->first_database_message_id) { // database definitely has no messages from first_database_message_id to last_database_message_id; drop them set_dialog_first_database_message_id(d, MessageId(), "on_get_history_from_database 8"); set_dialog_last_database_message_id(d, MessageId(), "on_get_history_from_database 9"); } else { - CHECK(last_received_message_id.is_valid()); + CHECK(first_received_message_id.is_valid()); // if a message was received, but wasn't added, then it is likely to be already deleted // if it is less than d->last_database_message_id, then we can adjust d->last_database_message_id and // try again database search without chance to loop - if (last_received_message_id < d->last_database_message_id) { - set_dialog_last_database_message_id(d, last_received_message_id, "on_get_history_from_database 12"); + if (first_received_message_id < d->last_database_message_id) { + set_dialog_last_database_message_id(d, first_received_message_id, "on_get_history_from_database 12"); - get_history_from_the_end_impl(d, true, only_local, std::move(promise)); + get_history_from_the_end_impl(d, true, only_local, std::move(promise), "on_get_history_from_database 21"); return; } if (limit > 1) { // we expected to have messages [first_database_message_id, last_database_message_id] in the database, but - // received no messages or newer messages [last_received_message_id, ...], none of which can be added + // received messages [first_received_message_id, last_received_message_id], none of which can be added // first_database_message_id and last_database_message_id are very wrong, so it is better to drop them, // pretending that the database has no usable messages - if (last_received_message_id == MessageId::max()) { + if (first_received_message_id == MessageId::max()) { + CHECK(last_received_message_id == MessageId()); LOG(ERROR) << "Receive no usable messages in " << dialog_id - << " from database from the end, but expected messages from " << d->last_database_message_id - << " up to " << d->first_database_message_id; + << " from database from the end, but expected messages from " << d->first_database_message_id + << " up to " << d->last_database_message_id + << ". Have old last_database_message_id = " << old_last_database_message_id << " and " + << messages.size() << " received messages"; } else { - LOG(ERROR) << "Receive " << messages.size() << " unusable messages up to " << last_received_message_id - << " in " << dialog_id << " from database from the end, but expected messages from " - << d->last_database_message_id << " up to " << d->first_database_message_id; + LOG(ERROR) << "Receive " << messages.size() << " unusable messages [" << first_received_message_id << " ... " + << last_received_message_id << "] in " << dialog_id + << " from database from the end, but expected messages from " << d->first_database_message_id + << " up to " << d->last_database_message_id; } set_dialog_first_database_message_id(d, MessageId(), "on_get_history_from_database 13"); set_dialog_last_database_message_id(d, MessageId(), "on_get_history_from_database 14"); @@ -23821,7 +23837,7 @@ void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId } } if (first_added_message_id.is_valid() && first_added_message_id != d->first_database_message_id && - last_received_message_id < d->first_database_message_id && d->last_new_message_id.is_valid() && + first_received_message_id < d->first_database_message_id && d->last_new_message_id.is_valid() && !d->have_full_history) { CHECK(first_added_message_id > d->first_database_message_id); set_dialog_first_database_message_id(d, first_added_message_id, "on_get_history_from_database 10"); @@ -23839,11 +23855,12 @@ void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId void MessagesManager::get_history_from_the_end(DialogId dialog_id, bool from_database, bool only_local, Promise &&promise) { - get_history_from_the_end_impl(get_dialog(dialog_id), from_database, only_local, std::move(promise)); + get_history_from_the_end_impl(get_dialog(dialog_id), from_database, only_local, std::move(promise), + "get_history_from_the_end"); } void MessagesManager::get_history_from_the_end_impl(const Dialog *d, bool from_database, bool only_local, - Promise &&promise) { + Promise &&promise, const char *source) { CHECK(d != nullptr); TRY_STATUS_PROMISE(promise, G()->close_status()); @@ -23861,7 +23878,7 @@ void MessagesManager::get_history_from_the_end_impl(const Dialog *d, bool from_d // repair last database message ID limit = 10; } - LOG(INFO) << "Get history from the end of " << dialog_id << " from database"; + LOG(INFO) << "Get history from the end of " << dialog_id << " from database from " << source; MessagesDbMessagesQuery db_query; db_query.dialog_id = dialog_id; db_query.from_message_id = MessageId::max(); @@ -23885,7 +23902,7 @@ void MessagesManager::get_history_from_the_end_impl(const Dialog *d, bool from_d limit = 10; } - LOG(INFO) << "Get history from the end of " << dialog_id << " from server"; + LOG(INFO) << "Get history from the end of " << dialog_id << " from server from " << source; td_->create_handler(std::move(promise)) ->send_get_from_the_end(dialog_id, d->last_new_message_id, limit); } @@ -23962,7 +23979,7 @@ void MessagesManager::load_messages_impl(const Dialog *d, MessageId from_message bool from_database = (left_tries > 2 || only_local) && G()->parameters().use_message_db; if (from_message_id == MessageId()) { - get_history_from_the_end_impl(d, from_database, only_local, std::move(promise)); + get_history_from_the_end_impl(d, from_database, only_local, std::move(promise), "load_messages_impl"); return; } if ((!d->first_database_message_id.is_valid() || from_message_id <= d->first_database_message_id) && @@ -32906,7 +32923,7 @@ void MessagesManager::on_send_dialog_action_timeout(DialogId dialog_id) { return; } CHECK(m->message_id.is_yet_unsent()); - if (m->forward_info != nullptr || m->had_forward_info || m->message_id.is_scheduled() || + if (m->forward_info != nullptr || m->had_forward_info || m->is_copy || m->message_id.is_scheduled() || m->sender_dialog_id.is_valid()) { return; } @@ -36380,7 +36397,8 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab d->last_new_message_id = MessageId(); } if (last_message_id.is_valid()) { - if ((last_message_id.is_server() || dialog_type == DialogType::SecretChat) && !d->last_new_message_id.is_valid()) { + if ((last_message_id.is_server() || dialog_type == DialogType::SecretChat) && !last_message_id.is_yet_unsent() && + !d->last_new_message_id.is_valid()) { LOG(ERROR) << "Bugfixing wrong last_new_message_id to " << last_message_id << " in " << dialog_id; // must be called before set_dialog_first_database_message_id and set_dialog_last_database_message_id set_dialog_last_new_message_id(d, last_message_id, "fix_new_dialog 1"); @@ -36418,19 +36436,24 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab } }; + auto last_message_date = last_database_message->date; if (dependent_dialog_count == 0) { - add_dialog_last_database_message(d, std::move(last_database_message)); + if (!add_dialog_last_database_message(d, std::move(last_database_message))) { + // failed to add last message; keep the current position and get history from the database + d->pending_last_message_date = last_message_date; + d->pending_last_message_id = last_message_id; + } } else { // can't add message immediately, because need to notify first about adding of dependent dialogs - d->pending_last_message_date = last_database_message->date; - d->pending_last_message_id = last_database_message->message_id; + d->pending_last_message_date = last_message_date; + d->pending_last_message_id = last_message_id; pending_add_dialog_last_database_message_[dialog_id] = {dependent_dialog_count, std::move(last_database_message)}; } } else if (last_database_message_id.is_valid()) { auto date = DialogDate(order, dialog_id).get_date(); if (date < MIN_PINNED_DIALOG_DATE) { d->pending_last_message_date = date; - d->pending_last_message_id = last_database_message_id; + d->pending_last_message_id = last_message_id; } } @@ -36558,7 +36581,7 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab if (need_get_history && !td_->auth_manager_->is_bot() && dialog_id != being_added_dialog_id_ && dialog_id != being_added_by_new_message_dialog_id_ && have_input_peer(dialog_id, AccessRights::Read) && (d->order != DEFAULT_ORDER || is_dialog_sponsored(d))) { - get_history_from_the_end_impl(d, true, false, Auto()); + get_history_from_the_end_impl(d, true, false, Auto(), "fix_new_dialog"); } if (d->need_repair_server_unread_count && need_unread_counter(d->order)) { CHECK(dialog_type != DialogType::SecretChat); @@ -36569,7 +36592,7 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr &&last_datab } } -void MessagesManager::add_dialog_last_database_message(Dialog *d, unique_ptr &&last_database_message) { +bool MessagesManager::add_dialog_last_database_message(Dialog *d, unique_ptr &&last_database_message) { CHECK(d != nullptr); CHECK(last_database_message != nullptr); CHECK(last_database_message->left == nullptr); @@ -36608,13 +36631,14 @@ void MessagesManager::add_dialog_last_database_message(Dialog *d, unique_ptrauth_manager_->is_bot() && dialog_id != being_added_dialog_id_ && dialog_id != being_added_by_new_message_dialog_id_ && have_input_peer(dialog_id, AccessRights::Read) && (d->order != DEFAULT_ORDER || is_dialog_sponsored(d))) { - get_history_from_the_end_impl(d, true, false, Auto()); + get_history_from_the_end_impl(d, true, false, Auto(), "add_dialog_last_database_message 5"); } } if (need_update_dialog_pos) { - update_dialog_pos(d, "add_dialog_last_database_message 5"); + update_dialog_pos(d, "add_dialog_last_database_message 6"); } + return m != nullptr; } void MessagesManager::update_dialogs_hints(const Dialog *d) { @@ -38192,10 +38216,13 @@ void MessagesManager::on_get_channel_difference( } // bots can receive channelDifferenceEmpty with pts bigger than known pts - LOG_IF(ERROR, request_pts != difference->pts_ && !td_->auth_manager_->is_bot()) - << "Receive channelDifferenceEmpty as result of getChannelDifference with pts = " << request_pts - << " and limit = " << request_limit << " in " << dialog_id << ", but pts has changed from " << request_pts - << " to " << difference->pts_; + // also, this can happen for deleted channels + if (request_pts != difference->pts_ && !td_->auth_manager_->is_bot() && + have_input_peer(dialog_id, AccessRights::Read)) { + LOG(ERROR) << "Receive channelDifferenceEmpty as result of getChannelDifference with pts = " << request_pts + << " and limit = " << request_limit << " in " << dialog_id << ", but pts has changed to " + << difference->pts_; + } set_channel_pts(d, difference->pts_, "channel difference empty"); break; } @@ -38429,7 +38456,7 @@ void MessagesManager::after_get_channel_difference(DialogId dialog_id, bool succ if (d != nullptr && !td_->auth_manager_->is_bot() && have_access && !d->last_message_id.is_valid() && !d->is_empty && (d->order != DEFAULT_ORDER || is_dialog_sponsored(d))) { - get_history_from_the_end_impl(d, true, false, Auto()); + get_history_from_the_end_impl(d, true, false, Auto(), "after_get_channel_difference"); } } @@ -39501,7 +39528,7 @@ void MessagesManager::suffix_load_loop(Dialog *d) { get_history_impl(d, from_message_id, -1, 100, true, true, std::move(promise)); } else { CHECK(from_message_id == MessageId()); - get_history_from_the_end_impl(d, true, true, std::move(promise)); + get_history_from_the_end_impl(d, true, true, std::move(promise), "suffix_load_loop"); } } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 175a188ce..229ab5b45 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -2235,7 +2235,8 @@ class MessagesManager final : public Actor { void get_history_from_the_end(DialogId dialog_id, bool from_database, bool only_local, Promise &&promise); - void get_history_from_the_end_impl(const Dialog *d, bool from_database, bool only_local, Promise &&promise); + void get_history_from_the_end_impl(const Dialog *d, bool from_database, bool only_local, Promise &&promise, + const char *source); void get_history(DialogId dialog_id, MessageId from_message_id, int32 offset, int32 limit, bool from_database, bool only_local, Promise &&promise); @@ -2694,7 +2695,7 @@ class MessagesManager final : public Actor { DialogId default_join_group_call_as_dialog_id, DialogId default_send_message_as_dialog_id, bool need_drop_default_send_message_as_dialog_id, bool is_loaded_from_database); - void add_dialog_last_database_message(Dialog *d, unique_ptr &&last_database_message); + bool add_dialog_last_database_message(Dialog *d, unique_ptr &&last_database_message); void fix_dialog_action_bar(const Dialog *d, DialogActionBar *action_bar); diff --git a/td/telegram/NotificationManager.cpp b/td/telegram/NotificationManager.cpp index 0d6ad6ceb..92c07c4aa 100644 --- a/td/telegram/NotificationManager.cpp +++ b/td/telegram/NotificationManager.cpp @@ -3205,7 +3205,7 @@ Status NotificationManager::process_push_notification_payload(string payload, bo return Status::Error("Receive wrong chat type"); } - if (begins_with(loc_key, "CHAT_MESSAGE") || loc_key == "CHAT_ALBUM") { + if (begins_with(loc_key, "CHAT_MESSAGE") || begins_with(loc_key, "CHAT_REACT") || loc_key == "CHAT_ALBUM") { loc_key = loc_key.substr(5); } if (loc_args.empty()) { @@ -3236,6 +3236,11 @@ Status NotificationManager::process_push_notification_payload(string payload, bo return Status::Error(406, "Phone call notification is not supported"); } + if (begins_with(loc_key, "REACT_")) { + // TODO REACT_* notifications + return Status::Error(406, "Reaction notifications are unsupported"); + } + loc_key = convert_loc_key(loc_key); if (loc_key.empty()) { return Status::Error("Push type is unknown"); diff --git a/td/telegram/NotificationSettingsManager.cpp b/td/telegram/NotificationSettingsManager.cpp index 17c693bb7..07320b361 100644 --- a/td/telegram/NotificationSettingsManager.cpp +++ b/td/telegram/NotificationSettingsManager.cpp @@ -1458,22 +1458,6 @@ void NotificationSettingsManager::get_notify_settings_exceptions(NotificationSet td_->create_handler(std::move(promise))->send(scope, filter_scope, compare_sound); } -void NotificationSettingsManager::after_get_difference() { - if (td_->auth_manager_->is_bot()) { - return; - } - - if (!users_notification_settings_.is_synchronized) { - send_get_scope_notification_settings_query(NotificationSettingsScope::Private, Promise<>()); - } - if (!chats_notification_settings_.is_synchronized) { - send_get_scope_notification_settings_query(NotificationSettingsScope::Group, Promise<>()); - } - if (!channels_notification_settings_.is_synchronized) { - send_get_scope_notification_settings_query(NotificationSettingsScope::Channel, Promise<>()); - } -} - void NotificationSettingsManager::on_binlog_events(vector &&events) { if (G()->close_flag()) { return; diff --git a/td/telegram/NotificationSettingsManager.h b/td/telegram/NotificationSettingsManager.h index f4b7dcaa5..26437ea1c 100644 --- a/td/telegram/NotificationSettingsManager.h +++ b/td/telegram/NotificationSettingsManager.h @@ -95,8 +95,6 @@ class NotificationSettingsManager final : public Actor { void init(); - void after_get_difference(); - void on_binlog_events(vector &&events); void get_current_state(vector> &updates) const; diff --git a/td/telegram/Payments.cpp b/td/telegram/Payments.cpp index 96ef21013..82ebb7888 100644 --- a/td/telegram/Payments.cpp +++ b/td/telegram/Payments.cpp @@ -734,8 +734,7 @@ Result process_input_message_invoice( PhotoSize s; s.type = 'n'; - s.dimensions = - get_dimensions(input_invoice->photo_width_, input_invoice->photo_height_, "process_input_message_invoice"); + s.dimensions = get_dimensions(input_invoice->photo_width_, input_invoice->photo_height_, nullptr); s.size = input_invoice->photo_size_; // TODO use invoice_file_id size s.file_id = invoice_file_id; diff --git a/td/telegram/Photo.cpp b/td/telegram/Photo.cpp index df1aff573..2c77023ae 100644 --- a/td/telegram/Photo.cpp +++ b/td/telegram/Photo.cpp @@ -270,7 +270,7 @@ Photo get_encrypted_file_photo(FileManager *file_manager, unique_ptrw_, photo->h_, "get_encrypted_file_photo"); + s.dimensions = get_dimensions(photo->w_, photo->h_, nullptr); s.size = photo->size_; s.file_id = file_id; res.photos.push_back(s); diff --git a/td/telegram/PhotoSize.cpp b/td/telegram/PhotoSize.cpp index 204888bfa..f40c31324 100644 --- a/td/telegram/PhotoSize.cpp +++ b/td/telegram/PhotoSize.cpp @@ -25,7 +25,9 @@ namespace td { static uint16 get_dimension(int32 size, const char *source) { if (size < 0 || size > 65535) { - LOG(ERROR) << "Wrong image dimension = " << size << " from " << source; + if (source != nullptr) { + LOG(ERROR) << "Wrong image dimension = " << size << " from " << source; + } return 0; } return narrow_cast(size); @@ -179,7 +181,7 @@ PhotoSize get_secret_thumbnail_photo_size(FileManager *file_manager, BufferSlice } PhotoSize res; res.type = 't'; - res.dimensions = get_dimensions(width, height, "get_secret_thumbnail_photo_size"); + res.dimensions = get_dimensions(width, height, nullptr); res.size = narrow_cast(bytes.size()); // generate some random remote location to save diff --git a/td/telegram/PollManager.cpp b/td/telegram/PollManager.cpp index 36a3cec64..c46f28908 100644 --- a/td/telegram/PollManager.cpp +++ b/td/telegram/PollManager.cpp @@ -1292,6 +1292,9 @@ void PollManager::on_unload_poll_timeout(PollId poll_id) { if (!can_unload_poll(poll_id)) { return; } + if (!have_poll(poll_id)) { + return; + } LOG(INFO) << "Unload " << poll_id; @@ -1303,6 +1306,7 @@ void PollManager::on_unload_poll_timeout(PollId poll_id) { poll_voters_.erase(poll_id); loaded_from_database_polls_.erase(poll_id); + unload_poll_timeout_.cancel_timeout(poll_id.get()); } void PollManager::on_get_poll_results(PollId poll_id, uint64 generation, @@ -1422,38 +1426,41 @@ vector PollManager::get_poll_options( } PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptr &&poll_server, - tl_object_ptr &&poll_results) { + tl_object_ptr &&poll_results, const char *source) { bool is_bot = td_->auth_manager_->is_bot(); bool need_update_poll = poll_id.is_valid() && is_bot; if (!poll_id.is_valid() && poll_server != nullptr) { poll_id = PollId(poll_server->id_); } if (!poll_id.is_valid() || is_local_poll_id(poll_id)) { - LOG(ERROR) << "Receive " << poll_id << " from server: " << oneline(to_string(poll_server)) << " " + LOG(ERROR) << "Receive " << poll_id << " from " << source << ": " << oneline(to_string(poll_server)) << " " << oneline(to_string(poll_results)); return PollId(); } if (poll_server != nullptr && poll_server->id_ != poll_id.get()) { - LOG(ERROR) << "Receive poll " << poll_server->id_ << " instead of " << poll_id; + LOG(ERROR) << "Receive poll " << poll_server->id_ << " instead of " << poll_id << " from " << source; return PollId(); } constexpr size_t MAX_POLL_OPTIONS = 10; // server-side limit if (poll_server != nullptr && (poll_server->answers_.size() <= 1 || poll_server->answers_.size() > 10 * MAX_POLL_OPTIONS)) { - LOG(ERROR) << "Receive " << poll_id << " with wrong number of answers: " << to_string(poll_server); + LOG(ERROR) << "Receive " << poll_id << " from " << source + << " with wrong number of answers: " << to_string(poll_server); return PollId(); } if (poll_server != nullptr) { FlatHashSet option_data; for (auto &answer : poll_server->answers_) { if (answer->option_.empty()) { - LOG(ERROR) << "Receive " << poll_id << " with an empty option data: " << to_string(poll_server); + LOG(ERROR) << "Receive " << poll_id << " from " << source + << " with an empty option data: " << to_string(poll_server); return PollId(); } option_data.insert(answer->option_.as_slice()); } if (option_data.size() != poll_server->answers_.size()) { - LOG(ERROR) << "Receive " << poll_id << " with duplicate options: " << to_string(poll_server); + LOG(ERROR) << "Receive " << poll_id << " from " << source + << " with duplicate options: " << to_string(poll_server); return PollId(); } } @@ -1571,7 +1578,7 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptrflags_ & telegram_api::poll::MULTIPLE_CHOICE_MASK) != 0; bool is_quiz = (poll_server->flags_ & telegram_api::poll::QUIZ_MASK) != 0; if (is_quiz && allow_multiple_answers) { - LOG(ERROR) << "Receive quiz " << poll_id << " allowing multiple answers"; + LOG(ERROR) << "Receive quiz " << poll_id << " from " << source << " allowing multiple answers"; allow_multiple_answers = false; } if (allow_multiple_answers != poll->allow_multiple_answers) { @@ -1590,7 +1597,7 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptrtotal_voters_ != poll->total_voter_count) { poll->total_voter_count = poll_results->total_voters_; if (poll->total_voter_count < 0) { - LOG(ERROR) << "Receive " << poll->total_voter_count << " voters in " << poll_id; + LOG(ERROR) << "Receive " << poll->total_voter_count << " voters in " << poll_id << " from " << source; poll->total_voter_count = 0; } is_changed = true; @@ -1614,7 +1621,8 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptrcorrect_; if (is_correct) { if (correct_option_id != -1) { - LOG(ERROR) << "Receive more than 1 correct answers " << correct_option_id << " and " << option_index; + LOG(ERROR) << "Receive more than 1 correct answers " << correct_option_id << " and " << option_index + << " in " << poll_id << " from " << source; } correct_option_id = static_cast(option_index); } @@ -1623,21 +1631,23 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptrvoters_ < 0) { - LOG(ERROR) << "Receive " << poll_result->voters_ << " voters for an option in " << poll_id; + LOG(ERROR) << "Receive " << poll_result->voters_ << " voters for an option in " << poll_id << " from " + << source; poll_result->voters_ = 0; } if (option.is_chosen && poll_result->voters_ == 0) { - LOG(ERROR) << "Receive 0 voters for the chosen option in " << poll_id; + LOG(ERROR) << "Receive 0 voters for the chosen option in " << poll_id << " from " << source; poll_result->voters_ = 1; } if (poll_result->voters_ > poll->total_voter_count) { LOG(ERROR) << "Have only " << poll->total_voter_count << " poll voters, but there are " << poll_result->voters_ - << " voters for an option in " << poll_id; + << " voters for an option in " << poll_id << " from " << source; poll->total_voter_count = poll_result->voters_; } auto max_voter_count = std::numeric_limits::max() / narrow_cast(poll->options.size()) - 2; if (poll_result->voters_ > max_voter_count) { - LOG(ERROR) << "Have too many " << poll_result->voters_ << " poll voters for an option in " << poll_id; + LOG(ERROR) << "Have too many " << poll_result->voters_ << " poll voters for an option in " << poll_id + << " from " << source; poll_result->voters_ = max_voter_count; } if (poll_result->voters_ != option.voter_count) { @@ -1654,13 +1664,13 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptrtotal_voter_count > max_total_voter_count && max_total_voter_count != 0) { LOG(ERROR) << "Have only " << max_total_voter_count << " total poll voters, but there are " - << poll->total_voter_count << " voters in " << poll_id; + << poll->total_voter_count << " voters in " << poll_id << " from " << source; poll->total_voter_count = max_total_voter_count; } } auto entities = - get_message_entities(td_->contacts_manager_.get(), std::move(poll_results->solution_entities_), "on_get_poll"); + get_message_entities(td_->contacts_manager_.get(), std::move(poll_results->solution_entities_), source); auto status = fix_formatted_text(poll_results->solution_, entities, true, true, true, true, false); if (status.is_error()) { if (!clean_input_string(poll_results->solution_)) { @@ -1674,7 +1684,7 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptrcorrect_option_id != correct_option_id) { if (correct_option_id == -1 && poll->correct_option_id != -1) { LOG(ERROR) << "Can't change correct option of " << poll_id << " from " << poll->correct_option_id << " to " - << correct_option_id; + << correct_option_id << " from " << source; } else { poll->correct_option_id = correct_option_id; is_changed = true; @@ -1682,7 +1692,7 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptrexplanation != explanation && (!is_min || poll_server_is_closed)) { if (explanation.text.empty() && !poll->explanation.text.empty()) { - LOG(ERROR) << "Can't change known " << poll_id << " explanation to empty"; + LOG(ERROR) << "Can't change known " << poll_id << " explanation to empty from " << source ; } else { poll->explanation = std::move(explanation); is_changed = true; @@ -1690,10 +1700,10 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptris_anonymous && !recent_voter_user_ids.empty()) { - LOG(ERROR) << "Receive anonymous " << poll_id << " with recent voters " << recent_voter_user_ids; + LOG(ERROR) << "Receive anonymous " << poll_id << " with recent voters " << recent_voter_user_ids << " from " + << source; recent_voter_user_ids.clear(); } if (recent_voter_user_ids != poll->recent_voter_user_ids) { diff --git a/td/telegram/PollManager.h b/td/telegram/PollManager.h index 08d073c13..8057ca396 100644 --- a/td/telegram/PollManager.h +++ b/td/telegram/PollManager.h @@ -79,7 +79,7 @@ class PollManager final : public Actor { tl_object_ptr get_input_media(PollId poll_id) const; PollId on_get_poll(PollId poll_id, tl_object_ptr &&poll_server, - tl_object_ptr &&poll_results); + tl_object_ptr &&poll_results, const char *source); void on_get_poll_vote(PollId poll_id, UserId user_id, vector &&options); diff --git a/td/telegram/ReplyMarkup.cpp b/td/telegram/ReplyMarkup.cpp index 0ddc9dc2f..26815179e 100644 --- a/td/telegram/ReplyMarkup.cpp +++ b/td/telegram/ReplyMarkup.cpp @@ -442,18 +442,17 @@ static Result get_keyboard_button(tl_object_ptr(button->type_); auto user_id = LinkManager::get_link_user_id(button_type->url_); if (user_id.is_valid()) { - return Status::Error(400, "Link to a user can't be used in web app URL buttons"); + return Status::Error(400, "Link to a user can't be used in Web App URL buttons"); } auto r_url = LinkManager::check_link(button_type->url_, true, !G()->is_test_dc()); if (r_url.is_error()) { - return Status::Error(400, PSLICE() << "Inline keyboard button web app URL '" << button_type->url_ - << "' is invalid: " << r_url.error().message()); + return Status::Error(400, PSLICE() << "Keyboard button Web App " << r_url.error().message()); } current_button.type = KeyboardButton::Type::WebView; current_button.url = std::move(button_type->url_); @@ -491,8 +490,7 @@ static Result get_inline_keyboard_button(tl_object_ptrurl_); if (r_url.is_error()) { - return Status::Error(400, PSLICE() << "Inline keyboard button URL '" << button_type->url_ - << "' is invalid: " << r_url.error().message()); + return Status::Error(400, PSLICE() << "Inline keyboard button " << r_url.error().message()); } current_button.type = InlineKeyboardButton::Type::Url; current_button.data = r_url.move_as_ok(); @@ -541,8 +539,7 @@ static Result get_inline_keyboard_button(tl_object_ptrurl_, true); if (r_url.is_error()) { - return Status::Error(400, PSLICE() << "Inline keyboard button login URL '" << button_type->url_ - << "' is invalid: " << r_url.error().message()); + return Status::Error(400, PSLICE() << "Inline keyboard button login " << r_url.error().message()); } current_button.type = InlineKeyboardButton::Type::UrlAuth; current_button.data = r_url.move_as_ok(); @@ -573,17 +570,16 @@ static Result get_inline_keyboard_button(tl_object_ptr(button->type_); auto user_id = LinkManager::get_link_user_id(button_type->url_); if (user_id.is_valid()) { - return Status::Error(400, "Link to a user can't be used in web app URL buttons"); + return Status::Error(400, "Link to a user can't be used in Web App URL buttons"); } auto r_url = LinkManager::check_link(button_type->url_, true, !G()->is_test_dc()); if (r_url.is_error()) { - return Status::Error(400, PSLICE() << "Inline keyboard button web app URL '" << button_type->url_ - << "' is invalid: " << r_url.error().message()); + return Status::Error(400, PSLICE() << "Inline keyboard button Web App " << r_url.error().message()); } current_button.type = InlineKeyboardButton::Type::WebView; current_button.data = r_url.move_as_ok(); if (!clean_input_string(current_button.data)) { - return Status::Error(400, "Inline keyboard button web app URL must be encoded in UTF-8"); + return Status::Error(400, "Inline keyboard button Web App URL must be encoded in UTF-8"); } break; } diff --git a/td/telegram/SecretChatActor.cpp b/td/telegram/SecretChatActor.cpp index 2b4ab2bd0..3347aaaf3 100644 --- a/td/telegram/SecretChatActor.cpp +++ b/td/telegram/SecretChatActor.cpp @@ -950,6 +950,9 @@ Status SecretChatActor::do_inbound_message_decrypted_unchecked(unique_ptrdecrypted_message_layer); + if (message->decrypted_message_layer->message_->get_id() == secret_api::decryptedMessageService8::ID) { auto old = move_tl_object_as(message->decrypted_message_layer->message_); message->decrypted_message_layer->message_ = @@ -985,9 +988,6 @@ Status SecretChatActor::do_inbound_message_decrypted_unchecked(unique_ptrdecrypted_message_layer); - if (status.is_error()) { CHECK(status.code() == 2); // gap found do_inbound_message_decrypted_pending(std::move(message)); diff --git a/td/telegram/SecureValue.cpp b/td/telegram/SecureValue.cpp index 4a4895ad9..c9d844e41 100644 --- a/td/telegram/SecureValue.cpp +++ b/td/telegram/SecureValue.cpp @@ -713,7 +713,7 @@ static Result to_int32(Slice str) { int32 integer_value = 0; for (auto c : str) { if (!is_digit(c)) { - return Status::Error(PSLICE() << "Can't parse \"" << str << "\" as number"); + return Status::Error(400, PSLICE() << "Can't parse \"" << utf8_encode(str.str()) << "\" as number"); } integer_value = integer_value * 10 + c - '0'; } @@ -725,12 +725,12 @@ static Result> get_date_object(Slice date) { return nullptr; } if (date.size() > 10u || date.size() < 8u) { - return Status::Error(400, PSLICE() << "Date \"" << date << "\" has wrong length"); + return Status::Error(400, PSLICE() << "Date \"" << utf8_encode(date.str()) << "\" has wrong length"); } auto parts = full_split(date, '.'); if (parts.size() != 3 || parts[0].size() > 2 || parts[1].size() > 2 || parts[2].size() != 4 || parts[0].empty() || parts[1].empty()) { - return Status::Error(400, PSLICE() << "Date \"" << date << "\" has wrong parts"); + return Status::Error(400, PSLICE() << "Date \"" << utf8_encode(date.str()) << "\" has wrong parts"); } TRY_RESULT(day, to_int32(parts[0])); TRY_RESULT(month, to_int32(parts[1])); @@ -1196,7 +1196,7 @@ Result decrypt_secure_value(FileManager *file_manage res_credentials.hash = encrypted_secure_value.hash; switch (encrypted_secure_value.type) { case SecureValueType::None: - return Status::Error("Receive invalid Telegram Passport element"); + return Status::Error(400, "Receive invalid Telegram Passport element"); case SecureValueType::EmailAddress: case SecureValueType::PhoneNumber: res.data = encrypted_secure_value.data.data; diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index 21b6ac45a..6769583a8 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -5647,8 +5647,7 @@ Result> StickersManager::prepare_i if (format == StickerFormat::Tgs) { int32 width = for_thumbnail ? 100 : 512; - create_sticker(file_id, string(), PhotoSize(), get_dimensions(width, width, "prepare_input_file"), nullptr, format, - nullptr); + create_sticker(file_id, string(), PhotoSize(), get_dimensions(width, width, nullptr), nullptr, format, nullptr); } else if (format == StickerFormat::Webm) { td_->documents_manager_->create_document(file_id, string(), PhotoSize(), "sticker.webm", "video/webm", false); } else { diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index d3c314188..14ad39740 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -33,6 +33,7 @@ #include "td/telegram/net/DcOptions.h" #include "td/telegram/net/NetQuery.h" #include "td/telegram/NotificationManager.h" +#include "td/telegram/NotificationSettings.h" #include "td/telegram/NotificationSettingsManager.h" #include "td/telegram/Payments.h" #include "td/telegram/PollId.h" @@ -1601,7 +1602,6 @@ void UpdatesManager::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(); send_closure_later(td_->notification_manager_actor_, &NotificationManager::after_get_difference); send_closure(G()->state_manager(), &StateManager::on_synchronized, true); get_difference_start_time_ = 0.0; @@ -1648,6 +1648,12 @@ void UpdatesManager::try_reload_data() { 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_->notification_settings_manager_->send_get_scope_notification_settings_query(NotificationSettingsScope::Private, + Auto()); + td_->notification_settings_manager_->send_get_scope_notification_settings_query(NotificationSettingsScope::Group, + Auto()); + td_->notification_settings_manager_->send_get_scope_notification_settings_query(NotificationSettingsScope::Channel, + Auto()); td_->stickers_manager_->reload_reactions(); td_->stickers_manager_->get_installed_sticker_sets(false, Auto()); td_->stickers_manager_->get_installed_sticker_sets(true, Auto()); @@ -1773,6 +1779,7 @@ void UpdatesManager::on_pending_updates(vectorget_id(); @@ -1781,11 +1788,13 @@ void UpdatesManager::on_pending_updates(vector } void UpdatesManager::on_update(tl_object_ptr update, Promise &&promise) { - td_->poll_manager_->on_get_poll(PollId(update->poll_id_), std::move(update->poll_), std::move(update->results_)); + td_->poll_manager_->on_get_poll(PollId(update->poll_id_), std::move(update->poll_), std::move(update->results_), + "updateMessagePoll"); promise.set_value(Unit()); } diff --git a/td/telegram/files/FileData.h b/td/telegram/files/FileData.h index ba3819ecf..f9eddf0bf 100644 --- a/td/telegram/files/FileData.h +++ b/td/telegram/files/FileData.h @@ -39,9 +39,8 @@ class FileData { }; inline StringBuilder &operator<<(StringBuilder &sb, const FileData &file_data) { - sb << "[" << tag("remote_name", file_data.remote_name_) << " " << file_data.owner_dialog_id_ << " " - << tag("size", file_data.size_) << tag("expected_size", file_data.expected_size_) << " " - << file_data.encryption_key_; + sb << "[" << tag("remote_name", file_data.remote_name_) << " " << tag("size", file_data.size_) + << tag("expected_size", file_data.expected_size_) << " " << file_data.encryption_key_; if (!file_data.url_.empty()) { sb << tag("url", file_data.url_); } diff --git a/td/telegram/files/FileManager.cpp b/td/telegram/files/FileManager.cpp index df0be24f8..e4682533d 100644 --- a/td/telegram/files/FileManager.cpp +++ b/td/telegram/files/FileManager.cpp @@ -43,6 +43,7 @@ #include "td/utils/Time.h" #include "td/utils/tl_helpers.h" #include "td/utils/tl_parsers.h" +#include "td/utils/utf8.h" #include #include @@ -990,27 +991,29 @@ Status FileManager::check_local_location(FullLocalFileLocation &location, int64 } else if (!are_modification_times_equal(location.mtime_nsec_, stat.mtime_nsec_)) { VLOG(file_loader) << "File \"" << location.path_ << "\" was modified: old mtime = " << location.mtime_nsec_ << ", new mtime = " << stat.mtime_nsec_; - return Status::Error(400, PSLICE() << "File \"" << location.path_ << "\" was modified"); + return Status::Error(400, PSLICE() << "File \"" << utf8_encode(location.path_) << "\" was modified"); } if (skip_file_size_checks) { return Status::OK(); } + + auto get_file_size_error = [&](Slice reason) { + return Status::Error(400, PSLICE() << "File \"" << utf8_encode(location.path_) << "\" of size " << size + << " bytes is too big" << reason); + }; if ((location.file_type_ == FileType::Thumbnail || location.file_type_ == FileType::EncryptedThumbnail) && size > MAX_THUMBNAIL_SIZE && !begins_with(PathView(location.path_).file_name(), "map")) { - return Status::Error(400, PSLICE() << "File \"" << location.path_ << "\" is too big for a thumbnail " - << tag("size", format::as_size(size))); + return get_file_size_error(" for a thumbnail"); } if (size > MAX_FILE_SIZE) { - return Status::Error(400, PSLICE() << "File \"" << location.path_ << "\" of size " << size << " bytes is too big"); + return get_file_size_error(""); } if (location.file_type_ == FileType::Photo && size > MAX_PHOTO_SIZE) { - return Status::Error( - 400, PSLICE() << "File \"" << location.path_ << "\" of size " << size << " bytes is too big for a photo"); + return get_file_size_error(" for a photo"); } if (location.file_type_ == FileType::VideoNote && size > G()->shared_config().get_option_integer("video_note_size_max", DEFAULT_VIDEO_NOTE_SIZE_MAX)) { - return Status::Error( - 400, PSLICE() << "File \"" << location.path_ << "\" of size " << size << " bytes is too big for a video note"); + return get_file_size_error(" for a video note"); } return Status::OK(); } diff --git a/td/telegram/td_json_client.h b/td/telegram/td_json_client.h index b694412da..e27a3bae7 100644 --- a/td/telegram/td_json_client.h +++ b/td/telegram/td_json_client.h @@ -91,7 +91,7 @@ TDJSON_EXPORT const char *td_execute(const char *request); * \param verbosity_level Log verbosity level with which the message was added (-1 - 1024). * If 0, then TDLib will crash as soon as the callback returns. * None of the TDLib methods can be called from the callback. - * \param message Null-terminated string with the logged message. + * \param message Null-terminated string with the logged message. The string isn't guaranteed to be encoded in UTF-8. */ typedef void (*td_log_message_callback_ptr)(int verbosity_level, const char *message); diff --git a/tdutils/td/utils/crypto.cpp b/tdutils/td/utils/crypto.cpp index 7541b9e09..ad1281518 100644 --- a/tdutils/td/utils/crypto.cpp +++ b/tdutils/td/utils/crypto.cpp @@ -1113,7 +1113,10 @@ Status create_openssl_error(int code, Slice message) { void clear_openssl_errors(Slice source) { if (ERR_peek_error() != 0) { - LOG(ERROR) << source << ": " << create_openssl_error(0, "Unprocessed OPENSSL_ERROR"); + auto error = create_openssl_error(0, "Unprocessed OPENSSL_ERROR"); + if (!ends_with(error.message(), ":def_load:system lib}]")) { + LOG(ERROR) << source << ": " << error; + } } #if TD_PORT_WINDOWS WSASetLastError(0); diff --git a/tdutils/td/utils/utf8.cpp b/tdutils/td/utils/utf8.cpp index 2990c5339..ff9a21fd3 100644 --- a/tdutils/td/utils/utf8.cpp +++ b/tdutils/td/utils/utf8.cpp @@ -7,6 +7,8 @@ #include "td/utils/utf8.h" #include "td/utils/logging.h" +#include "td/utils/misc.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/unicode.h" namespace td { @@ -121,4 +123,11 @@ string utf8_to_lower(Slice str) { return result; } +string utf8_encode(CSlice data) { + if (check_utf8(data)) { + return data.str(); + } + return PSTRING() << "url_decode(" << url_encode(data) << ')'; +} + } // namespace td diff --git a/tdutils/td/utils/utf8.h b/tdutils/td/utils/utf8.h index b48992953..e16eef4d1 100644 --- a/tdutils/td/utils/utf8.h +++ b/tdutils/td/utils/utf8.h @@ -118,4 +118,7 @@ T utf8_utf16_substr(T str, size_t offset, size_t length) { /// Returns UTF-8 string converted to lower case. string utf8_to_lower(Slice str); +/// Returns valid UTF-8 representation of the string. +string utf8_encode(CSlice data); + } // namespace td