diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 2e7008e47..ce5e1e344 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2228,6 +2228,10 @@ sendChatSetTtlMessage chat_id:int53 ttl:int32 = Message; //@description Sends a notification about a screenshot taken in a chat. Supported only in private and secret chats @chat_id Chat identifier sendChatScreenshotTakenNotification chat_id:int53 = Ok; +//@description Adds a local message to a chat. The message is persistent across application restarts only if the message database is used. Returns the added message @chat_id Target chat +//@reply_to_message_id Identifier of the message to reply to or 0 @input_message_content The content of the message to be added +addLocalMessage chat_id:int53 reply_to_message_id:int53 input_message_content:InputMessageContent = Message; + //@description Deletes messages @chat_id Chat identifier @message_ids Identifiers of the messages to be deleted @revoke Pass true to try to delete outgoing messages for all chat members (may fail if messages are too old). Always true for supergroups, channels and secret chats deleteMessages chat_id:int53 message_ids:vector revoke:Bool = Ok; @@ -2683,7 +2687,7 @@ pinSupergroupMessage supergroup_id:int32 message_id:int53 disable_notification:B //@description Removes the pinned message from a supergroup or channel; requires appropriate administrator rights in the supergroup or channel @supergroup_id Identifier of the supergroup or channel unpinSupergroupMessage supergroup_id:int32 = Ok; -//@description Reports some messages from a user in a supergroup as spam @supergroup_id Supergroup identifier @user_id User identifier @message_ids Identifiers of messages sent in the supergroup by the user. This list must be non-empty +//@description Reports some messages from a user in a supergroup as spam; requires administrator rights in the supergroup or channel @supergroup_id Supergroup identifier @user_id User identifier @message_ids Identifiers of messages sent in the supergroup by the user. This list must be non-empty reportSupergroupSpam supergroup_id:int32 user_id:int32 message_ids:vector = Ok; //@description Returns information about members or banned users in a supergroup or channel. Can be used only if SupergroupFullInfo.can_get_members == true; additionally, administrator privileges may be required for some filters @supergroup_id Identifier of the supergroup or channel diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index 4b7b647b2..2d67cab66 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index ccce8abfa..2cb2a5dfe 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -5262,8 +5262,11 @@ MessagesManager::Dialog *MessagesManager::get_service_notifications_dialog() { UserId service_notifications_user_id(777000); if (!td_->contacts_manager_->have_user_force(service_notifications_user_id) || !td_->contacts_manager_->have_user(service_notifications_user_id)) { + int32 flags = telegram_api::user::ACCESS_HASH_MASK | telegram_api::user::FIRST_NAME_MASK | + telegram_api::user::LAST_NAME_MASK | telegram_api::user::PHONE_MASK | telegram_api::user::PHOTO_MASK | + telegram_api::user::VERIFIED_MASK; auto user = telegram_api::make_object( - 131127, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, + flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, 777000, 1, "Telegram", "Updates", string(), "42777", telegram_api::make_object( @@ -15556,15 +15559,15 @@ Result MessagesManager::send_message(DialogId dialog_id, MessageId re m->is_content_secret = is_secret_message_content(m->ttl, m->content->get_id()); } + if (message_content.clear_draft) { + update_dialog_draft_message(d, nullptr, false, !need_update_dialog_pos); + } + send_update_new_message(d, m, true); if (need_update_dialog_pos) { send_update_chat_last_message(d, "send_message"); } - if (message_content.clear_draft) { - update_dialog_draft_message(d, nullptr, false, true); - } - auto message_id = m->message_id; save_send_message_logevent(dialog_id, m); do_send_message(dialog_id, m); @@ -18057,6 +18060,87 @@ void MessagesManager::do_send_screenshot_taken_notification_message(DialogId dia td_->create_handler(std::move(promise))->send(dialog_id, random_id); } +Result MessagesManager::add_local_message( + DialogId dialog_id, MessageId reply_to_message_id, + tl_object_ptr &&input_message_content) { + if (input_message_content == nullptr) { + return Status::Error(5, "Can't add local message without content"); + } + + LOG(INFO) << "Begin to add local message to " << dialog_id << " in reply to " << reply_to_message_id; + if (input_message_content->get_id() == td_api::inputMessageForwarded::ID) { + return Status::Error(5, "Can't add forwarded local message"); + } + if (input_message_content->get_id() == td_api::inputMessageGame::ID) { + return Status::Error(5, "Can't add local game message"); + } + + Dialog *d = get_dialog_force(dialog_id); + if (d == nullptr) { + return Status::Error(5, "Chat not found"); + } + + TRY_STATUS(can_send_message(dialog_id)); + TRY_RESULT(message_content, process_input_message_content(dialog_id, std::move(input_message_content))); + + MessageId message_id = get_next_local_message_id(d); + + auto dialog_type = dialog_id.get_type(); + auto my_id = td_->contacts_manager_->get_my_id("add_local_message"); + + auto m = make_unique(); + m->random_y = get_random_y(message_id); + m->message_id = message_id; + bool is_channel_post = is_broadcast_channel(dialog_id); + if (is_channel_post) { + // sender of the post can be hidden + if (td_->contacts_manager_->get_channel_sign_messages(dialog_id.get_channel_id())) { + m->author_signature = td_->contacts_manager_->get_user_title(my_id); + } + } else { + m->sender_user_id = my_id; + } + m->date = G()->unix_time(); + m->reply_to_message_id = get_reply_to_message_id(d, reply_to_message_id); + m->is_channel_post = is_channel_post; + m->is_outgoing = dialog_id != DialogId(my_id); + m->from_background = false; + m->views = 0; + m->content = std::move(message_content.content); + m->disable_web_page_preview = message_content.disable_web_page_preview; + m->clear_draft = message_content.clear_draft; + if (dialog_type == DialogType::SecretChat) { + m->ttl = td_->contacts_manager_->get_secret_chat_ttl(dialog_id.get_secret_chat_id()); + if (is_service_message_content(m->content->get_id())) { + m->ttl = 0; + } + m->is_content_secret = is_secret_message_content(m->ttl, m->content->get_id()); + } else if (message_content.ttl > 0) { + m->ttl = message_content.ttl; + } + m->is_content_secret = is_secret_message_content(m->ttl, m->content->get_id()); + + m->have_previous = true; + m->have_next = true; + + bool need_update = false; + bool need_update_dialog_pos = false; + auto result = + add_message_to_dialog(d, std::move(m), false, &need_update, &need_update_dialog_pos, "add local message"); + CHECK(result != nullptr); + + if (message_content.clear_draft) { + update_dialog_draft_message(d, nullptr, false, !need_update_dialog_pos); + } + + send_update_new_message(d, result, true); + if (need_update_dialog_pos) { + send_update_chat_last_message(d, "add_local_message"); + } + + return message_id; +} + bool MessagesManager::on_update_message_id(int64 random_id, MessageId new_message_id, const string &source) { if (!new_message_id.is_valid()) { LOG(ERROR) << "Receive " << new_message_id << " in update message id with random_id " << random_id << " from " diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 7b4d84254..64eb2cd05 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -1032,6 +1032,10 @@ class MessagesManager : public Actor { Status send_screenshot_taken_notification_message(DialogId dialog_id); + Result add_local_message(DialogId dialog_id, MessageId reply_to_message_id, + tl_object_ptr &&input_message_content) + TD_WARN_UNUSED_RESULT; + void edit_message_text(FullMessageId full_message_id, tl_object_ptr &&reply_markup, tl_object_ptr &&input_message_content, Promise &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index a150e6cca..9d52f8718 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5638,6 +5638,22 @@ void Td::on_request(uint64 id, const td_api::sendChatSetTtlMessage &request) { messages_manager_->get_message_object({dialog_id, r_new_message_id.ok()})); } +void Td::on_request(uint64 id, td_api::addLocalMessage &request) { + CHECK_AUTH(); + CHECK_IS_USER(); + + DialogId dialog_id(request.chat_id_); + auto r_new_message_id = messages_manager_->add_local_message(dialog_id, MessageId(request.reply_to_message_id_), + std::move(request.input_message_content_)); + if (r_new_message_id.is_error()) { + return send_closure(actor_id(this), &Td::send_error, id, r_new_message_id.move_as_error()); + } + + CHECK(r_new_message_id.ok().is_valid()); + send_closure(actor_id(this), &Td::send_result, id, + messages_manager_->get_message_object({dialog_id, r_new_message_id.ok()})); +} + void Td::on_request(uint64 id, td_api::editMessageText &request) { CHECK_AUTH(); CREATE_REQUEST(EditMessageTextRequest, request.chat_id_, request.message_id_, std::move(request.reply_markup_), diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 69595ef15..aef2ab4ab 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -479,6 +479,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::sendChatSetTtlMessage &request); + void on_request(uint64 id, td_api::addLocalMessage &request); + void on_request(uint64 id, td_api::editMessageText &request); void on_request(uint64 id, td_api::editMessageLiveLocation &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index ec69f8265..8785c78e5 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2069,6 +2069,26 @@ class CliClient final : public Actor { chat_id, make_tl_object(move_tl_object_as(parsed_text), false, true), op == "sms", false, as_message_id(reply_to_message_id)); + } else if (op == "alm" || op == "almr") { + string chat_id; + string reply_to_message_id; + string message; + + std::tie(chat_id, message) = split(args); + if (op == "smr") { + std::tie(reply_to_message_id, message) = split(message); + } + + auto parsed_text = + execute(make_tl_object(message, make_tl_object())); + if (parsed_text->get_id() == td_api::error::ID) { + parsed_text = make_tl_object(message, vector>()); + } + + send_request(make_tl_object( + as_chat_id(chat_id), as_message_id(reply_to_message_id), + make_tl_object(move_tl_object_as(parsed_text), false, + true))); } else if (op == "smap" || op == "smapr") { string chat_id; string reply_to_message_id; diff --git a/test/secure_storage.cpp b/test/secure_storage.cpp index 09c8f4982..3f4a540c0 100644 --- a/test/secure_storage.cpp +++ b/test/secure_storage.cpp @@ -61,10 +61,10 @@ TEST(SecureStorage, simple) { td::unlink(value_path).ignore(); td::unlink(encrypted_path).ignore(); td::unlink(decrypted_path).ignore(); - std::string value(100000, 'a'); - td::write_file(value_path, value); + std::string file_value(100000, 'a'); + td::write_file(value_path, file_value); auto hash = encrypt_file(value_secret, value_path, encrypted_path).move_as_ok(); decrypt_file(value_secret, hash, encrypted_path, decrypted_path).ensure(); - ASSERT_TRUE(td::read_file(decrypted_path).move_as_ok().as_slice() == value); + ASSERT_TRUE(td::read_file(decrypted_path).move_as_ok().as_slice() == file_value); } }