diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 192ae0b..fdfaf42 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3194,6 +3194,55 @@ class Client::TdOnCheckMessageCallback final : public TdQueryCallback { OnSuccess on_success_; }; +template +class Client::TdOnCheckMessageThreadCallback final : public TdQueryCallback { + public: + TdOnCheckMessageThreadCallback(Client *client, int64 chat_id, int64 message_thread_id, int64 reply_to_message_id, + PromisedQueryPtr query, OnSuccess on_success) + : client_(client) + , chat_id_(chat_id) + , message_thread_id_(message_thread_id) + , reply_to_message_id_(reply_to_message_id) + , query_(std::move(query)) + , on_success_(std::move(on_success)) { + } + + void on_result(object_ptr result) final { + if (result->get_id() == td_api::error::ID) { + auto error = move_object_as(result); + if (error->code_ == 429) { + LOG(WARNING) << "Failed to get message thread " << message_thread_id_ << " in " << chat_id_; + } + return fail_query_with_error(std::move(query_), std::move(error), "Message thread not found"); + } + + CHECK(result->get_id() == td_api::message::ID); + auto full_message_id = client_->add_message(move_object_as(result)); + CHECK(full_message_id.chat_id == chat_id_); + CHECK(full_message_id.message_id == message_thread_id_); + + const MessageInfo *message_info = client_->get_message(chat_id_, message_thread_id_); + CHECK(message_info != nullptr); + if (message_info->message_thread_id != message_thread_id_) { + return fail_query_with_error(std::move(query_), 400, "MESSAGE_THREAD_INVALID", "Message thread not found"); + } + if (!message_info->is_topic_message) { + return fail_query_with_error(std::move(query_), 400, "MESSAGE_THREAD_INVALID", + "Message thread is not a forum topic thread"); + } + + on_success_(chat_id_, message_thread_id_, reply_to_message_id_, std::move(query_)); + } + + private: + Client *client_; + int64 chat_id_; + int64 message_thread_id_; + int64 reply_to_message_id_; + PromisedQueryPtr query_; + OnSuccess on_success_; +}; + template class Client::TdOnCheckRemoteFileIdCallback final : public TdQueryCallback { public: @@ -4381,6 +4430,30 @@ void Client::check_message(Slice chat_id_str, int64 message_id, bool allow_empty }); } +template +void Client::check_message_thread(int64 chat_id, int64 message_thread_id, int64 reply_to_message_id, + PromisedQueryPtr query, OnSuccess on_success) { + if (message_thread_id <= 0) { + return on_success(chat_id, 0, reply_to_message_id, std::move(query)); + } + + if (reply_to_message_id != 0) { + const MessageInfo *message_info = get_message(chat_id, reply_to_message_id); + CHECK(message_info != nullptr); + if (message_info->message_thread_id != message_thread_id) { + return fail_query_with_error(std::move(query), 400, "MESSAGE_THREAD_INVALID", + "Replied message is not in the specified message thread"); + } + } + if (reply_to_message_id == message_thread_id) { + return on_success(chat_id, message_thread_id, reply_to_message_id, std::move(query)); + } + + send_request(make_object(chat_id, message_thread_id), + td::make_unique>( + this, chat_id, message_thread_id, reply_to_message_id, std::move(query), std::move(on_success))); +} + template void Client::resolve_sticker_set(const td::string &sticker_set_name, PromisedQueryPtr query, OnSuccess on_success) { if (sticker_set_name.empty()) { @@ -7542,16 +7615,23 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { input_message_contents = std::move(input_message_contents), reply_markup = std::move(reply_markup)](int64 chat_id, int64 reply_to_message_id, 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 query->set_retry_after_error(60); - } + auto on_message_thread_checked = + [this, disable_notification, protect_content, input_message_contents = std::move(input_message_contents), + reply_markup = std::move(reply_markup)](int64 chat_id, int64 message_thread_id, + int64 reply_to_message_id, 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 query->set_retry_after_error(60); + } - send_request( - make_object(chat_id, message_thread_id, reply_to_message_id, - get_message_send_options(disable_notification, protect_content), - std::move(input_message_contents), false), - td::make_unique(this, std::move(query))); + send_request(make_object( + chat_id, message_thread_id, reply_to_message_id, + get_message_send_options(disable_notification, protect_content), + std::move(input_message_contents), false), + td::make_unique(this, std::move(query))); + }; + check_message_thread(chat_id, message_thread_id, reply_to_message_id, std::move(query), + std::move(on_message_thread_checked)); }; check_message(chat_id, reply_to_message_id, reply_to_message_id <= 0 || allow_sending_without_reply, AccessRights::Write, "replied message", std::move(query), std::move(on_success)); @@ -9112,15 +9192,23 @@ void Client::do_send_message(object_ptr input_messa input_message_content = std::move(input_message_content), reply_markup = std::move(reply_markup)](int64 chat_id, int64 reply_to_message_id, 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 query->set_retry_after_error(60); - } + auto on_message_thread_checked = + [this, disable_notification, protect_content, input_message_content = std::move(input_message_content), + reply_markup = std::move(reply_markup)](int64 chat_id, int64 message_thread_id, + int64 reply_to_message_id, 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 query->set_retry_after_error(60); + } - send_request(make_object(chat_id, message_thread_id, reply_to_message_id, - get_message_send_options(disable_notification, protect_content), - std::move(reply_markup), std::move(input_message_content)), - td::make_unique(this, std::move(query))); + send_request( + make_object(chat_id, message_thread_id, reply_to_message_id, + get_message_send_options(disable_notification, protect_content), + std::move(reply_markup), std::move(input_message_content)), + td::make_unique(this, std::move(query))); + }; + check_message_thread(chat_id, message_thread_id, reply_to_message_id, std::move(query), + std::move(on_message_thread_checked)); }; check_message(chat_id, reply_to_message_id, reply_to_message_id <= 0 || allow_sending_without_reply, AccessRights::Write, "replied message", std::move(query), std::move(on_success)); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 555eb8f..bf5f57c 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -250,6 +250,8 @@ class Client final : public WebhookActor::Callback { template class TdOnCheckMessageCallback; template + class TdOnCheckMessageThreadCallback; + template class TdOnCheckRemoteFileIdCallback; template class TdOnGetChatMemberCallback; @@ -288,6 +290,10 @@ class Client final : public WebhookActor::Callback { void check_message(Slice chat_id_str, int64 message_id, bool allow_empty, AccessRights access_rights, Slice message_type, PromisedQueryPtr query, OnSuccess on_success); + template + void check_message_thread(int64 chat_id, int64 message_thread_id, int64 reply_to_message_id, PromisedQueryPtr query, + OnSuccess on_success); + template void resolve_sticker_set(const td::string &sticker_set_name, PromisedQueryPtr query, OnSuccess on_success);