diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 182d24c..3ebca6e 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -252,6 +252,7 @@ bool Client::init_methods() { methods_.emplace("stoppoll", &Client::process_stop_poll_query); methods_.emplace("copymessage", &Client::process_copy_message_query); methods_.emplace("forwardmessage", &Client::process_forward_message_query); + methods_.emplace("forwardmessages", &Client::process_forward_messages_query); methods_.emplace("sendmediagroup", &Client::process_send_media_group_query); methods_.emplace("sendchataction", &Client::process_send_chat_action_query); methods_.emplace("editmessagetext", &Client::process_edit_message_text_query); @@ -3963,6 +3964,44 @@ class Client::TdOnSendMessageAlbumCallback final : public TdQueryCallback { PromisedQueryPtr query_; }; +class Client::TdOnForwardMessagesCallback final : public TdQueryCallback { + public: + TdOnForwardMessagesCallback(Client *client, int64 chat_id, std::size_t message_count, PromisedQueryPtr query) + : client_(client), chat_id_(chat_id), message_count_(message_count), query_(std::move(query)) { + } + + void on_result(object_ptr result) final { + if (result->get_id() == td_api::error::ID) { + if (message_count_ > 0) { + client_->decrease_yet_unsent_message_count(chat_id_, static_cast(message_count_)); + } + return fail_query_with_error(std::move(query_), move_object_as(result)); + } + + CHECK(result->get_id() == td_api::messages::ID); + auto messages = move_object_as(result); + CHECK(messages->messages_.size() == message_count_); + td::remove_if(messages->messages_, [](const auto &message) { return message == nullptr; }); + if (messages->messages_.size() != message_count_) { + client_->decrease_yet_unsent_message_count(chat_id_, + static_cast(message_count_ - messages->messages_.size())); + } + if (messages->messages_.empty()) { + return fail_query_with_error(std::move(query_), 400, "Messages can't be forwarded"); + } + auto query_id = client_->get_send_message_query_id(std::move(query_), true); + for (auto &message : messages->messages_) { + client_->on_sent_message(std::move(message), query_id); + } + } + + private: + Client *client_; + int64 chat_id_; + std::size_t message_count_; + PromisedQueryPtr query_; +}; + class Client::TdOnDeleteFailedToSendMessageCallback final : public TdQueryCallback { public: TdOnDeleteFailedToSendMessageCallback(Client *client, int64 chat_id, int64 message_id) @@ -9346,7 +9385,11 @@ void Client::on_message_send_succeeded(object_ptr &&message, in auto query_id = extract_yet_unsent_message_query_id(chat_id, old_message_id); auto &query = *pending_send_message_queries_[query_id]; if (query.is_multisend) { - query.messages.push_back(td::json_encode(JsonMessage(message_info, true, "sent message", this))); + if (query.query->method() == "forwardmessages") { + query.messages.push_back(td::json_encode(JsonMessageId(new_message_id))); + } else { + query.messages.push_back(td::json_encode(JsonMessage(message_info, true, "sent message", this))); + } query.awaited_message_count--; if (query.awaited_message_count == 0) { @@ -9926,6 +9969,48 @@ td::Status Client::process_forward_message_query(PromisedQueryPtr &query) { return td::Status::OK(); } +td::Status Client::process_forward_messages_query(PromisedQueryPtr &query) { + auto chat_id = query->arg("chat_id"); + auto message_thread_id = get_message_id(query.get(), "message_thread_id"); + TRY_RESULT(from_chat_id, get_required_string_arg(query.get(), "from_chat_id")); + TRY_RESULT(message_ids, get_message_ids(query.get(), 100)); + if (message_ids.empty()) { + return td::Status::Error(400, "Message identifiers are not specified"); + } + auto disable_notification = to_bool(query->arg("disable_notification")); + auto protect_content = to_bool(query->arg("protect_content")); + + auto on_success = [this, from_chat_id = from_chat_id.str(), message_ids = std::move(message_ids), + disable_notification, protect_content](int64 chat_id, int64 message_thread_id, + CheckedReplyParameters, PromisedQueryPtr query) mutable { + auto it = yet_unsent_message_count_.find(chat_id); + if (it != yet_unsent_message_count_.end() && it->second >= MAX_CONCURRENTLY_SENT_CHAT_MESSAGES) { + return fail_query_flood_limit_exceeded(std::move(query)); + } + + check_messages( + from_chat_id, std::move(message_ids), true, AccessRights::Read, "message to forward", std::move(query), + [this, chat_id, message_thread_id, disable_notification, protect_content]( + int64 from_chat_id, td::vector message_ids, PromisedQueryPtr query) { + auto &count = yet_unsent_message_count_[chat_id]; + if (count >= MAX_CONCURRENTLY_SENT_CHAT_MESSAGES) { + return fail_query_flood_limit_exceeded(std::move(query)); + } + + auto message_count = message_ids.size(); + count += static_cast(message_count); + + send_request(make_object( + chat_id, message_thread_id, from_chat_id, std::move(message_ids), + get_message_send_options(disable_notification, protect_content), false, false), + td::make_unique(this, chat_id, message_count, std::move(query))); + }); + }; + check_reply_parameters(chat_id, InputReplyParameters(), message_thread_id, std::move(query), std::move(on_success)); + + return td::Status::OK(); +} + td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); auto message_thread_id = get_message_id(query.get(), "message_thread_id"); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 54bc373..09cc421 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -70,7 +70,7 @@ class Client final : public WebhookActor::Callback { static constexpr int32 MAX_CERTIFICATE_FILE_SIZE = 3 << 20; static constexpr int32 MAX_DOWNLOAD_FILE_SIZE = 20 << 20; - static constexpr int32 MAX_CONCURRENTLY_SENT_CHAT_MESSAGES = 250; // some unreasonably big value + static constexpr int32 MAX_CONCURRENTLY_SENT_CHAT_MESSAGES = 310; // some unreasonably big value static constexpr std::size_t MIN_PENDING_UPDATES_WARNING = 200; @@ -213,6 +213,7 @@ class Client final : public WebhookActor::Callback { class TdOnGetUserProfilePhotosCallback; class TdOnSendMessageCallback; class TdOnSendMessageAlbumCallback; + class TdOnForwardMessagesCallback; class TdOnDeleteFailedToSendMessageCallback; class TdOnEditMessageCallback; class TdOnEditInlineMessageCallback; @@ -656,6 +657,7 @@ class Client final : public WebhookActor::Callback { td::Status process_stop_poll_query(PromisedQueryPtr &query); td::Status process_copy_message_query(PromisedQueryPtr &query); td::Status process_forward_message_query(PromisedQueryPtr &query); + td::Status process_forward_messages_query(PromisedQueryPtr &query); td::Status process_send_media_group_query(PromisedQueryPtr &query); td::Status process_send_chat_action_query(PromisedQueryPtr &query); td::Status process_edit_message_text_query(PromisedQueryPtr &query);