diff --git a/CMakeLists.txt b/CMakeLists.txt index 29bec4b..5709f9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 5.4.1 LANGUAGES CXX) +project(TelegramBotApi VERSION 5.5 LANGUAGES CXX) if (POLICY CMP0069) option(TELEGRAM_BOT_API_ENABLE_LTO "Use \"ON\" to enable Link Time Optimization.") diff --git a/td b/td index 1bd9e0f..a53cb30 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 1bd9e0f622346ad95c774a774d85ea855567d46c +Subproject commit a53cb30e99f937cfd64e0266fa558785a184a553 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 563dfa7..4ebd1a6 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -278,6 +278,8 @@ bool Client::init_methods() { methods_.emplace("kickchatmember", &Client::process_ban_chat_member_query); methods_.emplace("restrictchatmember", &Client::process_restrict_chat_member_query); methods_.emplace("unbanchatmember", &Client::process_unban_chat_member_query); + methods_.emplace("banchatsenderchat", &Client::process_ban_chat_sender_chat_query); + methods_.emplace("unbanchatsenderchat", &Client::process_unban_chat_sender_chat_query); methods_.emplace("approvechatjoinrequest", &Client::process_approve_chat_join_request_query); methods_.emplace("declinechatjoinrequest", &Client::process_decline_chat_join_request_query); methods_.emplace("getstickerset", &Client::process_get_sticker_set_query); @@ -714,6 +716,9 @@ class Client::JsonChat : public Jsonable { if (!user_info->bio.empty()) { object("bio", user_info->bio); } + if (user_info->has_private_forwards) { + object("has_private_forwards", td::JsonTrue()); + } } break; } @@ -818,6 +823,9 @@ class Client::JsonChat : public Jsonable { if (chat_info->message_auto_delete_time != 0) { object("message_auto_delete_time", chat_info->message_auto_delete_time); } + if (chat_info->has_protected_content) { + object("has_protected_content", td::JsonTrue()); + } } // start custom properties impl @@ -838,18 +846,19 @@ class Client::JsonChat : public Jsonable { class Client::JsonMessageSender : public Jsonable { public: - JsonMessageSender(const td_api::MessageSender *sender, const Client *client) : sender_(sender), client_(client) { + JsonMessageSender(const td_api::MessageSender *sender_id, const Client *client) + : sender_id_(sender_id), client_(client) { } void store(JsonValueScope *scope) const { - CHECK(sender_ != nullptr); - switch (sender_->get_id()) { + CHECK(sender_id_ != nullptr); + switch (sender_id_->get_id()) { case td_api::messageSenderUser::ID: { - auto sender_user_id = static_cast(sender_)->user_id_; + auto sender_user_id = static_cast(sender_id_)->user_id_; JsonUser(sender_user_id, client_).store(scope); break; } case td_api::messageSenderChat::ID: { - auto sender_chat_id = static_cast(sender_)->chat_id_; + auto sender_chat_id = static_cast(sender_id_)->chat_id_; JsonChat(sender_chat_id, false, client_).store(scope); break; } @@ -859,7 +868,7 @@ class Client::JsonMessageSender : public Jsonable { } private: - const td_api::MessageSender *sender_; + const td_api::MessageSender *sender_id_; const Client *client_; }; @@ -1518,8 +1527,8 @@ class Client::JsonProximityAlertTriggered : public Jsonable { } void store(JsonValueScope *scope) const { auto object = scope->enter_object(); - object("traveler", JsonMessageSender(proximity_alert_triggered_->traveler_.get(), client_)); - object("watcher", JsonMessageSender(proximity_alert_triggered_->watcher_.get(), client_)); + object("traveler", JsonMessageSender(proximity_alert_triggered_->traveler_id_.get(), client_)); + object("watcher", JsonMessageSender(proximity_alert_triggered_->watcher_id_.get(), client_)); object("distance", proximity_alert_triggered_->distance_); } @@ -1642,6 +1651,11 @@ class Client::JsonInlineKeyboardButton : public Jsonable { case td_api::inlineKeyboardButtonTypeBuy::ID: object("pay", td::JsonTrue()); break; + case td_api::inlineKeyboardButtonTypeUser::ID: { + auto type = static_cast(button_->type_.get()); + object("url", PSLICE() << "tg://user?id=" << type->user_id_); + break; + } default: UNREACHABLE(); break; @@ -1736,6 +1750,9 @@ void Client::JsonMessage::store(JsonValueScope *scope) const { if (!message_->initial_sender_name.empty()) { object("forward_sender_name", message_->initial_sender_name); } + if (message_->is_automatic_forward) { + object("is_automatic_forward", td::JsonTrue()); + } object("forward_date", message_->initial_send_date); } if (message_->reply_to_message_id > 0 && need_reply_ && !message_->is_reply_to_message_deleted) { @@ -2031,6 +2048,9 @@ void Client::JsonMessage::store(JsonValueScope *scope) const { if (message_->via_bot_user_id > 0) { object("via_bot", JsonUser(message_->via_bot_user_id, client_)); } + if (!message_->can_be_saved) { + object("has_protected_content", td::JsonTrue()); + } } class Client::JsonDeletedMessage : public Jsonable { @@ -3211,6 +3231,23 @@ class Client::TdOnOptimizeMemoryCallback : public TdQueryCallback { OnSuccess on_success_; }; +template +class Client::TdOnCheckChatNoFailCallback : public TdQueryCallback { + public: + TdOnCheckChatNoFailCallback(int64 chat_id, PromisedQueryPtr query, OnSuccess on_success) + : chat_id_(chat_id), query_(std::move(query)), on_success_(std::move(on_success)) { + } + + void on_result(object_ptr result) override { + on_success_(chat_id_, std::move(query_)); + } + + private: + int64 chat_id_; + PromisedQueryPtr query_; + OnSuccess on_success_; +}; + template class Client::TdOnSearchStickerSetCallback : public TdQueryCallback { public: @@ -4399,6 +4436,26 @@ void Client::check_chat(Slice chat_id_str, AccessRights access_rights, PromisedQ std::move(on_success))); } +template +void Client::check_chat_no_fail(Slice chat_id_str, PromisedQueryPtr query, OnSuccess on_success) { + if (chat_id_str.empty()) { + return fail_query(400, "Bad Request: sedner_chat_id is empty", std::move(query)); + } + + auto r_chat_id = td::to_integer_safe(chat_id_str); + if (r_chat_id.is_error()) { + return fail_query(400, "Bad Request: sedner_chat_id is not a valid Integer", std::move(query)); + } + auto chat_id = r_chat_id.move_as_ok(); + + auto chat_info = get_chat(chat_id); + if (chat_info != nullptr) { + return on_success(chat_id, std::move(query)); + } + send_request(make_object(chat_id), std::make_unique>( + chat_id, std::move(query), std::move(on_success))); +} + template void Client::check_bot_command_scope(BotCommandScope &&scope, PromisedQueryPtr query, OnSuccess on_success) { CHECK(scope.scope_ != nullptr); @@ -4953,6 +5010,7 @@ void Client::on_update(object_ptr result) { chat_info->photo = std::move(chat->photo_); chat_info->permissions = std::move(chat->permissions_); chat_info->message_auto_delete_time = chat->message_ttl_setting_; + chat_info->has_protected_content = chat->has_protected_content_; break; } case td_api::updateChatTitle::ID: { @@ -4983,6 +5041,13 @@ void Client::on_update(object_ptr result) { chat_info->message_auto_delete_time = update->message_ttl_setting_; break; } + case td_api::updateChatHasProtectedContent::ID: { + auto update = move_object_as(result); + auto chat_info = add_chat(update->chat_id_); + CHECK(chat_info->type != ChatInfo::Type::Unknown); + chat_info->has_protected_content = update->has_protected_content_; + break; + } case td_api::updateUser::ID: { auto update = move_object_as(result); add_user(users_, std::move(update->user_)); @@ -4992,6 +5057,7 @@ void Client::on_update(object_ptr result) { auto update = move_object_as(result); auto user_id = update->user_id_; set_user_bio(user_id, std::move(update->user_full_info_->bio_)); + set_user_has_private_forwards(user_id, update->user_full_info_->has_private_forwards_); break; } case td_api::updateBasicGroup::ID: { @@ -8470,13 +8536,49 @@ td::Status Client::process_unban_chat_member_query(PromisedQueryPtr &query) { return Status::OK(); } +td::Status Client::process_ban_chat_sender_chat_query(PromisedQueryPtr &query) { + auto chat_id = query->arg("chat_id"); + auto sender_chat_id = query->arg("sender_chat_id"); + int32 until_date = get_integer_arg(query.get(), "until_date", 0); + + check_chat(chat_id, AccessRights::Write, std::move(query), + [this, sender_chat_id = sender_chat_id.str(), until_date](int64 chat_id, PromisedQueryPtr query) { + check_chat_no_fail(sender_chat_id, std::move(query), + [this, chat_id, until_date](int64 sender_chat_id, PromisedQueryPtr query) { + send_request( + make_object( + chat_id, td_api::make_object(sender_chat_id), + until_date, false), + std::make_unique(std::move(query))); + }); + }); + return Status::OK(); +} + +td::Status Client::process_unban_chat_sender_chat_query(PromisedQueryPtr &query) { + auto chat_id = query->arg("chat_id"); + auto sender_chat_id = query->arg("sender_chat_id"); + + check_chat(chat_id, AccessRights::Write, std::move(query), + [this, sender_chat_id = sender_chat_id.str()](int64 chat_id, PromisedQueryPtr query) { + check_chat_no_fail( + sender_chat_id, std::move(query), [this, chat_id](int64 sender_chat_id, PromisedQueryPtr query) { + send_request(make_object( + chat_id, td_api::make_object(sender_chat_id), + make_object()), + std::make_unique(std::move(query))); + }); + }); + return Status::OK(); +} + td::Status Client::process_approve_chat_join_request_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); TRY_RESULT(user_id, get_user_id(query.get())); check_chat(chat_id, AccessRights::Write, std::move(query), [this, user_id](int64 chat_id, PromisedQueryPtr query) { check_user_no_fail(user_id, std::move(query), [this, chat_id, user_id](PromisedQueryPtr query) { - send_request(make_object(chat_id, user_id), + send_request(make_object(chat_id, user_id, true), std::make_unique(std::move(query))); }); }); @@ -8489,7 +8591,7 @@ td::Status Client::process_decline_chat_join_request_query(PromisedQueryPtr &que check_chat(chat_id, AccessRights::Write, std::move(query), [this, user_id](int64 chat_id, PromisedQueryPtr query) { check_user_no_fail(user_id, std::move(query), [this, chat_id, user_id](PromisedQueryPtr query) { - send_request(make_object(chat_id, user_id), + send_request(make_object(chat_id, user_id, false), std::make_unique(std::move(query))); }); }); @@ -9690,6 +9792,11 @@ void Client::set_user_bio(int64 user_id, td::string &&bio) { user_info->bio = std::move(bio); } +void Client::set_user_has_private_forwards(int64 user_id, bool has_private_forwards) { + auto user_info = &users_[user_id]; + user_info->has_private_forwards = has_private_forwards; +} + void Client::add_group(std::unordered_map &groups, object_ptr &&group) { auto group_info = &groups[group->id_]; group_info->member_count = group->member_count_; @@ -10373,8 +10480,8 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr(message->content_.get()); - return proximity_alert_triggered->traveler_->get_id() != td_api::messageSenderUser::ID || - proximity_alert_triggered->watcher_->get_id() != td_api::messageSenderUser::ID; + return proximity_alert_triggered->traveler_id_->get_id() != td_api::messageSenderUser::ID || + proximity_alert_triggered->watcher_id_->get_id() != td_api::messageSenderUser::ID; } case td_api::messageGameScore::ID: return true; @@ -10494,6 +10601,11 @@ bool Client::are_equal_inline_keyboard_buttons(const td_api::inlineKeyboardButto } case td_api::inlineKeyboardButtonTypeBuy::ID: return true; + case td_api::inlineKeyboardButtonTypeUser::ID: { + auto lhs_type = static_cast(lhs->type_.get()); + auto rhs_type = static_cast(rhs->type_.get()); + return lhs_type->user_id_ == rhs_type->user_id_; + } default: UNREACHABLE(); return false; @@ -10775,17 +10887,17 @@ Client::FullMessageId Client::add_message(object_ptr &&message, message_info->via_bot_user_id = message->via_bot_user_id_; message_info->message_thread_id = message->message_thread_id_; - CHECK(message->sender_ != nullptr); - switch (message->sender_->get_id()) { + CHECK(message->sender_id_ != nullptr); + switch (message->sender_id_->get_id()) { case td_api::messageSenderUser::ID: { - auto sender = move_object_as(message->sender_); - message_info->sender_user_id = sender->user_id_; + auto sender_id = move_object_as(message->sender_id_); + message_info->sender_user_id = sender_id->user_id_; CHECK(message_info->sender_user_id > 0); break; } case td_api::messageSenderChat::ID: { - auto sender = move_object_as(message->sender_); - message_info->sender_chat_id = sender->chat_id_; + auto sender_id = move_object_as(message->sender_id_); + message_info->sender_chat_id = sender_id->chat_id_; auto chat_type = get_chat_type(chat_id); if (chat_type != ChatType::Channel) { @@ -10844,6 +10956,9 @@ Client::FullMessageId Client::add_message(object_ptr &&message, default: UNREACHABLE(); } + message_info->is_automatic_forward = message_info->initial_chat_id != 0 && message_info->initial_message_id != 0 && + message_info->initial_chat_id == message->forward_info_->from_chat_id_ && + message_info->initial_message_id == message->forward_info_->from_message_id_; } if (message->interaction_info_ != nullptr) { @@ -10856,6 +10971,7 @@ Client::FullMessageId Client::add_message(object_ptr &&message, message_info->scheduled_at = scheduling_state->send_date_; } + message_info->can_be_saved = message->can_be_saved_; message_info->author_signature = std::move(message->author_signature_); if (message->reply_in_chat_id_ != chat_id && message->reply_to_message_id_ != 0) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 8070a5c..135918e 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -261,6 +261,8 @@ class Client : public WebhookActor::Callback { template class TdOnDisableInternetConnectionCallback; template + class TdOnCheckChatNoFailCallback; + template class TdOnCheckMessageCallback; template class TdOnCheckRemoteFileIdCallback; @@ -296,6 +298,9 @@ class Client : public WebhookActor::Callback { void enable_internet_connection(PromisedQueryPtr query); + template + void check_chat_no_fail(Slice chat_id_str, PromisedQueryPtr query, OnSuccess on_success); + template void check_bot_command_scope(BotCommandScope &&scope, PromisedQueryPtr query, OnSuccess on_success); @@ -560,6 +565,8 @@ class Client : public WebhookActor::Callback { Status process_ban_chat_member_query(PromisedQueryPtr &query); Status process_restrict_chat_member_query(PromisedQueryPtr &query); Status process_unban_chat_member_query(PromisedQueryPtr &query); + Status process_ban_chat_sender_chat_query(PromisedQueryPtr &query); + Status process_unban_chat_sender_chat_query(PromisedQueryPtr &query); Status process_approve_chat_join_request_query(PromisedQueryPtr &query); Status process_decline_chat_join_request_query(PromisedQueryPtr &query); Status process_get_sticker_set_query(PromisedQueryPtr &query); @@ -686,9 +693,11 @@ class Client : public WebhookActor::Callback { bool can_join_groups = false; bool can_read_all_group_messages = false; bool is_inline_bot = false; + bool has_private_forwards = false; }; static void add_user(std::unordered_map &users, object_ptr &&user); void set_user_bio(int64 user_id, td::string &&bio); + void set_user_has_private_forwards(int64 user_id, bool has_private_forwards); const UserInfo *get_user_info(int64 user_id) const; struct GroupInfo { @@ -740,6 +749,7 @@ class Client : public WebhookActor::Callback { Type type = Type::Unknown; td::string title; int32 message_auto_delete_time = 0; + bool has_protected_content = false; object_ptr photo; object_ptr permissions; union { @@ -791,6 +801,8 @@ class Client : public WebhookActor::Callback { int32 scheduled_at = 0; // end custom properties + bool can_be_saved = false; + bool is_automatic_forward = false; mutable bool is_reply_to_message_deleted = false; mutable bool is_content_changed = false; }; diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index 6e2d129..6340dc1 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -37,6 +37,7 @@ #include "td/utils/misc.h" #include "td/utils/OptionParser.h" #include "td/utils/PathView.h" +#include "td/utils/port/detail/ThreadIdGuard.h" #include "td/utils/port/IPAddress.h" #include "td/utils/port/path.h" #include "td/utils/port/rlimit.h" @@ -172,6 +173,7 @@ static void dump_statistics(const std::shared_ptr &shared_data, int main(int argc, char *argv[]) { SET_VERBOSITY_LEVEL(VERBOSITY_NAME(FATAL)); td::ExitGuard exit_guard; + td::detail::ThreadIdGuard thread_id_guard; need_reopen_log.test_and_set(); need_quit.test_and_set(); @@ -198,7 +200,7 @@ int main(int argc, char *argv[]) { auto start_time = td::Time::now(); auto shared_data = std::make_shared(); auto parameters = std::make_unique(); - parameters->version_ = "5.4.1"; + parameters->version_ = "5.5"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats();