From 13d68879d31fa68a6654ab619a0c265f0c6df3df Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 9 Nov 2023 18:24:50 +0300 Subject: [PATCH 01/55] Add Client::get_same_chat_reply_to_message_id(const MessageInfo *message_info). --- telegram-bot-api/Client.cpp | 27 ++++++++++++++------------- telegram-bot-api/Client.h | 2 ++ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 1848b8a..d318d4c 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1983,8 +1983,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("forward_date", message_->initial_send_date); } if (need_reply_) { - auto reply_to_message_id = - get_same_chat_reply_to_message_id(message_->reply_to_message.get(), message_->message_thread_id); + auto reply_to_message_id = get_same_chat_reply_to_message_id(message_); if (reply_to_message_id > 0) { // internal reply const MessageInfo *reply_to_message = client_->get_message(message_->chat_id, reply_to_message_id, true); @@ -4478,8 +4477,7 @@ void Client::on_get_callback_query_message(object_ptr message, process_new_callback_query_queue(user_id, state); return; } - auto reply_to_message_id = - get_same_chat_reply_to_message_id(message_info->reply_to_message.get(), message_info->message_thread_id); + auto reply_to_message_id = get_same_chat_reply_to_message_id(message_info); LOG(INFO) << "Can't find callback query reply to message " << reply_to_message_id << " in chat " << chat_id << ". It may be already deleted"; } @@ -10965,10 +10963,7 @@ void Client::process_new_callback_query_queue(int64 user_id, int state) { state = 1; } if (state == 1) { - auto reply_to_message_id = message_info == nullptr - ? 0 - : get_same_chat_reply_to_message_id(message_info->reply_to_message.get(), - message_info->message_thread_id); + auto reply_to_message_id = get_same_chat_reply_to_message_id(message_info); if (reply_to_message_id > 0 && get_message(chat_id, reply_to_message_id, false) == nullptr) { queue.has_active_request_ = true; return send_request(make_object(chat_id, message_id), @@ -10983,10 +10978,7 @@ void Client::process_new_callback_query_queue(int64 user_id, int state) { return send_request(make_object(message_sticker_set_id), td::make_unique(this, message_sticker_set_id, user_id, 0)); } - auto reply_to_message_id = message_info == nullptr - ? 0 - : get_same_chat_reply_to_message_id(message_info->reply_to_message.get(), - message_info->message_thread_id); + auto reply_to_message_id = get_same_chat_reply_to_message_id(message_info); if (reply_to_message_id > 0) { auto reply_to_message_info = get_message(chat_id, reply_to_message_id, true); auto reply_sticker_set_id = @@ -11284,7 +11276,16 @@ td::int64 Client::get_same_chat_reply_to_message_id(const object_ptrreply_to_ == nullptr); return content_message_id; } - return get_same_chat_reply_to_message_id(message->reply_to_, message->message_thread_id_); + return get_same_chat_reply_to_message_id( + message->reply_to_, message->message_thread_id_ < message->id_ ? message->message_thread_id_ : 0); +} + +td::int64 Client::get_same_chat_reply_to_message_id(const MessageInfo *message_info) { + if (message_info == nullptr) { + return 0; + } + auto message_thread_id = message_info->message_thread_id < message_info->id ? message_info->message_thread_id : 0; + return get_same_chat_reply_to_message_id(message_info->reply_to_message.get(), message_thread_id); } void Client::drop_internal_reply_to_message_in_another_chat(object_ptr &message) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 4daa014..2f726f4 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -845,6 +845,8 @@ class Client final : public WebhookActor::Callback { static int64 get_same_chat_reply_to_message_id(const object_ptr &message); + static int64 get_same_chat_reply_to_message_id(const MessageInfo *message_info); + static void drop_internal_reply_to_message_in_another_chat(object_ptr &message); static td::Slice get_sticker_type(const object_ptr &type); From b81f8065d787fcc6a317e93942276b81b664e199 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 9 Nov 2023 19:15:42 +0300 Subject: [PATCH 02/55] Support td_api::textEntityTypeBlockQuote. --- telegram-bot-api/Client.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index d318d4c..338b439 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -512,6 +512,9 @@ class Client::JsonEntity final : public td::Jsonable { object("custom_emoji_id", td::to_string(entity->custom_emoji_id_)); break; } + case td_api::textEntityTypeBlockQuote::ID: + object("type", "blockquote"); + break; default: UNREACHABLE(); } @@ -532,8 +535,7 @@ class Client::JsonVectorEntities final : public td::Jsonable { for (auto &entity : entities_) { auto entity_type = entity->type_->get_id(); if (entity_type != td_api::textEntityTypeBankCardNumber::ID && - entity_type != td_api::textEntityTypeMediaTimestamp::ID && - entity_type != td_api::textEntityTypeBlockQuote::ID) { + entity_type != td_api::textEntityTypeMediaTimestamp::ID) { array << JsonEntity(entity.get(), client_); } } @@ -7239,6 +7241,9 @@ td::Result> Client::get_text_entity_t TRY_RESULT(custom_emoji_id, object.get_required_long_field("custom_emoji_id")); return make_object(custom_emoji_id); } + if (type == "blockquote") { + return make_object(); + } if (type == "mention" || type == "hashtag" || type == "cashtag" || type == "bot_command" || type == "url" || type == "email" || type == "phone_number" || type == "bank_card_number") { return nullptr; From 6a5393a9258c3b973ed266602df312ced34d0061 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 13 Nov 2023 18:22:04 +0300 Subject: [PATCH 03/55] Add Message.giveaway_created. --- telegram-bot-api/Client.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 338b439..e2b8c63 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2330,6 +2330,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { case td_api::messagePremiumGiftCode::ID: break; case td_api::messagePremiumGiveawayCreated::ID: + object("giveaway_created", JsonEmptyObject()); break; case td_api::messagePremiumGiveaway::ID: break; @@ -11106,6 +11107,7 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr Date: Mon, 13 Nov 2023 18:38:57 +0300 Subject: [PATCH 04/55] Add Message.giveaway. --- telegram-bot-api/Client.cpp | 41 ++++++++++++++++++++++++++++++++++--- telegram-bot-api/Client.h | 1 + 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index e2b8c63..5c4fc03 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1814,6 +1814,39 @@ class Client::JsonChatShared final : public td::Jsonable { const td_api::messageChatShared *chat_shared_; }; +class Client::JsonGiveaway final : public td::Jsonable { + public: + JsonGiveaway(const td_api::messagePremiumGiveaway *giveaway, const Client *client) + : giveaway_(giveaway), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + td::vector chat_ids; + chat_ids.push_back(giveaway_->parameters_->boosted_chat_id_); + for (auto chat_id : giveaway_->parameters_->additional_chat_ids_) { + chat_ids.push_back(chat_id); + } + object("chats", + td::json_array(chat_ids, [client = client_](auto &chat_id) { return JsonChat(chat_id, false, client); })); + object("winners_selection_date", giveaway_->parameters_->winners_selection_date_); + object("winner_count", giveaway_->winner_count_); + if (giveaway_->parameters_->only_new_members_) { + object("only_new_members", td::JsonTrue()); + } + if (!giveaway_->parameters_->country_codes_.empty()) { + object("country_codes", td::json_array(giveaway_->parameters_->country_codes_, + [](td::Slice country_code) { return td::JsonString(country_code); })); + } + if (giveaway_->month_count_ > 0) { + object("premium_subscription_month_count", giveaway_->month_count_); + } + } + + private: + const td_api::messagePremiumGiveaway *giveaway_; + const Client *client_; +}; + class Client::JsonWebAppInfo final : public td::Jsonable { public: explicit JsonWebAppInfo(const td::string &url) : url_(url) { @@ -2332,8 +2365,11 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { case td_api::messagePremiumGiveawayCreated::ID: object("giveaway_created", JsonEmptyObject()); break; - case td_api::messagePremiumGiveaway::ID: + case td_api::messagePremiumGiveaway::ID: { + auto content = static_cast(message_->content.get()); + object("giveaway", JsonGiveaway(content, client_)); break; + } case td_api::messageStory::ID: object("story", JsonEmptyObject()); break; @@ -11108,6 +11144,7 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr Date: Mon, 13 Nov 2023 18:53:04 +0300 Subject: [PATCH 05/55] Simplify update*FullInfo handling. --- telegram-bot-api/Client.cpp | 120 ++++++++---------------------------- telegram-bot-api/Client.h | 17 ----- 2 files changed, 24 insertions(+), 113 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 5c4fc03..ac5e542 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3727,7 +3727,7 @@ class Client::TdOnGetChatStickerSetCallback final : public TdQueryCallback { auto chat_info = client_->get_chat(chat_id_); CHECK(chat_info != nullptr); CHECK(chat_info->type == ChatInfo::Type::Supergroup); - client_->set_supergroup_sticker_set_id(chat_info->supergroup_id, 0); + client_->add_supergroup_info(chat_info->supergroup_id)->sticker_set_id = 0; } else { CHECK(result->get_id() == td_api::stickerSet::ID); auto sticker_set = move_object_as(result); @@ -5290,14 +5290,12 @@ void Client::on_update(object_ptr result) { auto update = move_object_as(result); auto user_id = update->user_id_; auto full_info = update->user_full_info_.get(); - set_user_photo(user_id, - full_info->photo_ == nullptr ? std::move(full_info->public_photo_) : std::move(full_info->photo_)); - if (full_info->bio_ != nullptr) { - set_user_bio(user_id, std::move(full_info->bio_->text_)); - } - set_user_has_private_forwards(user_id, full_info->has_private_forwards_); - set_user_has_restricted_voice_and_video_messages(user_id, - full_info->has_restricted_voice_and_video_note_messages_); + auto user_info = add_user_info(user_id); + user_info->photo = + full_info->photo_ == nullptr ? std::move(full_info->public_photo_) : std::move(full_info->photo_); + user_info->bio = full_info->bio_ != nullptr ? std::move(full_info->bio_->text_) : td::string(); + user_info->has_private_forwards = full_info->has_private_forwards_; + user_info->has_restricted_voice_and_video_messages = full_info->has_restricted_voice_and_video_note_messages_; break; } case td_api::updateBasicGroup::ID: { @@ -5310,11 +5308,11 @@ void Client::on_update(object_ptr result) { auto update = move_object_as(result); auto group_id = update->basic_group_id_; auto full_info = update->basic_group_full_info_.get(); - set_group_photo(group_id, std::move(full_info->photo_)); - set_group_description(group_id, std::move(full_info->description_)); - set_group_invite_link(group_id, full_info->invite_link_ != nullptr - ? std::move(full_info->invite_link_->invite_link_) - : td::string()); + auto group_info = add_group_info(group_id); + group_info->photo = std::move(full_info->photo_); + group_info->description = std::move(full_info->description_); + group_info->invite_link = std::move( + full_info->invite_link_ != nullptr ? std::move(full_info->invite_link_->invite_link_) : td::string()); break; } case td_api::updateSupergroup::ID: { @@ -5327,18 +5325,18 @@ void Client::on_update(object_ptr result) { auto update = move_object_as(result); auto supergroup_id = update->supergroup_id_; auto full_info = update->supergroup_full_info_.get(); - set_supergroup_photo(supergroup_id, std::move(full_info->photo_)); - set_supergroup_description(supergroup_id, std::move(full_info->description_)); - set_supergroup_invite_link(supergroup_id, full_info->invite_link_ != nullptr - ? std::move(full_info->invite_link_->invite_link_) - : td::string()); - set_supergroup_sticker_set_id(supergroup_id, full_info->sticker_set_id_); - set_supergroup_can_set_sticker_set(supergroup_id, full_info->can_set_sticker_set_); - set_supergroup_slow_mode_delay(supergroup_id, full_info->slow_mode_delay_); - set_supergroup_linked_chat_id(supergroup_id, full_info->linked_chat_id_); - set_supergroup_location(supergroup_id, std::move(full_info->location_)); - set_supergroup_has_hidden_members(supergroup_id, full_info->has_hidden_members_); - set_supergroup_has_aggressive_anti_spam_enabled(supergroup_id, full_info->has_aggressive_anti_spam_enabled_); + auto supergroup_info = add_supergroup_info(supergroup_id); + supergroup_info->photo = std::move(full_info->photo_); + supergroup_info->description = std::move(full_info->description_); + supergroup_info->invite_link = std::move( + full_info->invite_link_ != nullptr ? std::move(full_info->invite_link_->invite_link_) : td::string()); + supergroup_info->sticker_set_id = full_info->sticker_set_id_; + supergroup_info->can_set_sticker_set = full_info->can_set_sticker_set_; + supergroup_info->slow_mode_delay = full_info->slow_mode_delay_; + supergroup_info->linked_chat_id = full_info->linked_chat_id_; + supergroup_info->location = std::move(full_info->location_); + supergroup_info->has_hidden_members = full_info->has_hidden_members_; + supergroup_info->has_aggressive_anti_spam_enabled = full_info->has_aggressive_anti_spam_enabled_; break; } case td_api::updateOption::ID: { @@ -10458,23 +10456,6 @@ const Client::UserInfo *Client::get_user_info(int64 user_id) const { return users_.get_pointer(user_id); } -void Client::set_user_photo(int64 user_id, object_ptr &&photo) { - add_user_info(user_id)->photo = std::move(photo); -} - -void Client::set_user_bio(int64 user_id, td::string &&bio) { - add_user_info(user_id)->bio = std::move(bio); -} - -void Client::set_user_has_private_forwards(int64 user_id, bool has_private_forwards) { - add_user_info(user_id)->has_private_forwards = has_private_forwards; -} - -void Client::set_user_has_restricted_voice_and_video_messages(int64 user_id, - bool has_restricted_voice_and_video_messages) { - add_user_info(user_id)->has_restricted_voice_and_video_messages = has_restricted_voice_and_video_messages; -} - void Client::add_group(GroupInfo *group_info, object_ptr &&group) { group_info->member_count = group->member_count_; group_info->left = group->status_->get_id() == td_api::chatMemberStatusLeft::ID; @@ -10498,18 +10479,6 @@ const Client::GroupInfo *Client::get_group_info(int64 group_id) const { return groups_.get_pointer(group_id); } -void Client::set_group_photo(int64 group_id, object_ptr &&photo) { - add_group_info(group_id)->photo = std::move(photo); -} - -void Client::set_group_description(int64 group_id, td::string &&description) { - add_group_info(group_id)->description = std::move(description); -} - -void Client::set_group_invite_link(int64 group_id, td::string &&invite_link) { - add_group_info(group_id)->invite_link = std::move(invite_link); -} - void Client::add_supergroup(SupergroupInfo *supergroup_info, object_ptr &&supergroup) { if (supergroup->usernames_ == nullptr) { supergroup_info->active_usernames.clear(); @@ -10527,47 +10496,6 @@ void Client::add_supergroup(SupergroupInfo *supergroup_info, object_ptrjoin_by_request = supergroup->join_by_request_; } -void Client::set_supergroup_photo(int64 supergroup_id, object_ptr &&photo) { - add_supergroup_info(supergroup_id)->photo = std::move(photo); -} - -void Client::set_supergroup_description(int64 supergroup_id, td::string &&description) { - add_supergroup_info(supergroup_id)->description = std::move(description); -} - -void Client::set_supergroup_invite_link(int64 supergroup_id, td::string &&invite_link) { - add_supergroup_info(supergroup_id)->invite_link = std::move(invite_link); -} - -void Client::set_supergroup_sticker_set_id(int64 supergroup_id, int64 sticker_set_id) { - add_supergroup_info(supergroup_id)->sticker_set_id = sticker_set_id; -} - -void Client::set_supergroup_can_set_sticker_set(int64 supergroup_id, bool can_set_sticker_set) { - add_supergroup_info(supergroup_id)->can_set_sticker_set = can_set_sticker_set; -} - -void Client::set_supergroup_slow_mode_delay(int64 supergroup_id, int32 slow_mode_delay) { - add_supergroup_info(supergroup_id)->slow_mode_delay = slow_mode_delay; -} - -void Client::set_supergroup_linked_chat_id(int64 supergroup_id, int64 linked_chat_id) { - add_supergroup_info(supergroup_id)->linked_chat_id = linked_chat_id; -} - -void Client::set_supergroup_location(int64 supergroup_id, object_ptr location) { - add_supergroup_info(supergroup_id)->location = std::move(location); -} - -void Client::set_supergroup_has_hidden_members(int64 supergroup_id, bool has_hidden_members) { - add_supergroup_info(supergroup_id)->has_hidden_members = has_hidden_members; -} - -void Client::set_supergroup_has_aggressive_anti_spam_enabled(int64 supergroup_id, - bool has_aggressive_anti_spam_enabled) { - add_supergroup_info(supergroup_id)->has_aggressive_anti_spam_enabled = has_aggressive_anti_spam_enabled; -} - Client::SupergroupInfo *Client::add_supergroup_info(int64 supergroup_id) { auto &supergroup_info = supergroups_[supergroup_id]; if (supergroup_info == nullptr) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 645ac72..f7cb107 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -728,10 +728,6 @@ class Client final : public WebhookActor::Callback { bool added_to_attachment_menu = false; }; static void add_user(UserInfo *user_info, object_ptr &&user); - void set_user_photo(int64 user_id, object_ptr &&photo); - void set_user_bio(int64 user_id, td::string &&bio); - void set_user_has_private_forwards(int64 user_id, bool has_private_forwards); - void set_user_has_restricted_voice_and_video_messages(int64 user_id, bool has_restricted_voice_and_video_messages); UserInfo *add_user_info(int64 user_id); const UserInfo *get_user_info(int64 user_id) const; @@ -746,9 +742,6 @@ class Client final : public WebhookActor::Callback { int64 upgraded_to_supergroup_id = 0; }; static void add_group(GroupInfo *group_info, object_ptr &&group); - void set_group_photo(int64 group_id, object_ptr &&photo); - void set_group_description(int64 group_id, td::string &&description); - void set_group_invite_link(int64 group_id, td::string &&invite_link); GroupInfo *add_group_info(int64 group_id); const GroupInfo *get_group_info(int64 group_id) const; @@ -774,16 +767,6 @@ class Client final : public WebhookActor::Callback { bool has_aggressive_anti_spam_enabled = false; }; static void add_supergroup(SupergroupInfo *supergroup_info, object_ptr &&supergroup); - void set_supergroup_photo(int64 supergroup_id, object_ptr &&photo); - void set_supergroup_description(int64 supergroup_id, td::string &&description); - void set_supergroup_invite_link(int64 supergroup_id, td::string &&invite_link); - void set_supergroup_sticker_set_id(int64 supergroup_id, int64 sticker_set_id); - void set_supergroup_can_set_sticker_set(int64 supergroup_id, bool can_set_sticker_set); - void set_supergroup_slow_mode_delay(int64 supergroup_id, int32 slow_mode_delay); - void set_supergroup_linked_chat_id(int64 supergroup_id, int64 linked_chat_id); - void set_supergroup_location(int64 supergroup_id, object_ptr location); - void set_supergroup_has_hidden_members(int64 supergroup_id, bool has_hidden_members); - void set_supergroup_has_aggressive_anti_spam_enabled(int64 supergroup_id, bool has_aggressive_anti_spam_enabled); SupergroupInfo *add_supergroup_info(int64 supergroup_id); const SupergroupInfo *get_supergroup_info(int64 supergroup_id) const; From 704a4272dd6d65c654cbefd45b88defb684cd6ad Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 13 Nov 2023 18:56:15 +0300 Subject: [PATCH 06/55] Add Chat.has_visible_history. --- telegram-bot-api/Client.cpp | 4 ++++ telegram-bot-api/Client.h | 1 + 2 files changed, 5 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index ac5e542..ca9f0c0 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -800,6 +800,9 @@ class Client::JsonChat final : public td::Jsonable { if (supergroup_info->can_set_sticker_set) { object("can_set_sticker_set", td::JsonTrue()); } + if (supergroup_info->is_all_history_available) { + object("has_visible_history", td::JsonTrue()); + } if (supergroup_info->is_supergroup) { object("permissions", JsonChatPermissions(chat_info->permissions.get())); } @@ -5332,6 +5335,7 @@ void Client::on_update(object_ptr result) { full_info->invite_link_ != nullptr ? std::move(full_info->invite_link_->invite_link_) : td::string()); supergroup_info->sticker_set_id = full_info->sticker_set_id_; supergroup_info->can_set_sticker_set = full_info->can_set_sticker_set_; + supergroup_info->is_all_history_available = full_info->is_all_history_available_; supergroup_info->slow_mode_delay = full_info->slow_mode_delay_; supergroup_info->linked_chat_id = full_info->linked_chat_id_; supergroup_info->location = std::move(full_info->location_); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index f7cb107..c5a5b05 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -760,6 +760,7 @@ class Client final : public WebhookActor::Callback { bool is_supergroup = false; bool is_forum = false; bool can_set_sticker_set = false; + bool is_all_history_available = false; bool has_location = false; bool join_to_send_messages = false; bool join_by_request = false; From 282e31f5fc6dfc6a431fdbf1f28462ae9823edca Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 13 Nov 2023 19:08:21 +0300 Subject: [PATCH 07/55] Add Chat.accent_color_id. --- telegram-bot-api/Client.cpp | 10 ++++++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 11 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index ca9f0c0..41d10cf 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -877,6 +877,8 @@ class Client::JsonChat final : public td::Jsonable { if (chat_info->message_auto_delete_time != 0) { object("message_auto_delete_time", chat_info->message_auto_delete_time); } + CHECK(chat_info->accent_color_id != -1); + object("accent_color_id", chat_info->accent_color_id); if (chat_info->has_protected_content) { object("has_protected_content", td::JsonTrue()); } @@ -5245,6 +5247,7 @@ void Client::on_update(object_ptr result) { chat_info->photo_info = std::move(chat->photo_); chat_info->permissions = std::move(chat->permissions_); chat_info->message_auto_delete_time = chat->message_auto_delete_time_; + chat_info->accent_color_id = chat->accent_color_id_; chat_info->has_protected_content = chat->has_protected_content_; break; } @@ -5276,6 +5279,13 @@ void Client::on_update(object_ptr result) { chat_info->message_auto_delete_time = update->message_auto_delete_time_; break; } + case td_api::updateChatAccentColor::ID: { + auto update = move_object_as(result); + auto chat_info = add_chat(update->chat_id_); + CHECK(chat_info->type != ChatInfo::Type::Unknown); + chat_info->accent_color_id = update->accent_color_id_; + break; + } case td_api::updateChatHasProtectedContent::ID: { auto update = move_object_as(result); auto chat_info = add_chat(update->chat_id_); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index c5a5b05..03136b0 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -776,6 +776,7 @@ class Client final : public WebhookActor::Callback { Type type = Type::Unknown; td::string title; int32 message_auto_delete_time = 0; + int32 accent_color_id = -1; bool has_protected_content = false; object_ptr photo_info; object_ptr permissions; From 4bb770f31a17e2f2d9539d1e5b4df0e56b8b61bb Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 13 Nov 2023 19:15:19 +0300 Subject: [PATCH 08/55] Add Chat.background_custom_emoji_id. --- telegram-bot-api/Client.cpp | 11 +++++++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 12 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 41d10cf..df70bf5 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -879,6 +879,9 @@ class Client::JsonChat final : public td::Jsonable { } CHECK(chat_info->accent_color_id != -1); object("accent_color_id", chat_info->accent_color_id); + if (chat_info->background_custom_emoji_id != 0) { + object("background_custom_emoji_id", td::to_string(chat_info->background_custom_emoji_id)); + } if (chat_info->has_protected_content) { object("has_protected_content", td::JsonTrue()); } @@ -5248,6 +5251,7 @@ void Client::on_update(object_ptr result) { chat_info->permissions = std::move(chat->permissions_); chat_info->message_auto_delete_time = chat->message_auto_delete_time_; chat_info->accent_color_id = chat->accent_color_id_; + chat_info->background_custom_emoji_id = chat->background_custom_emoji_id_; chat_info->has_protected_content = chat->has_protected_content_; break; } @@ -5286,6 +5290,13 @@ void Client::on_update(object_ptr result) { chat_info->accent_color_id = update->accent_color_id_; break; } + case td_api::updateChatBackgroundCustomEmoji::ID: { + auto update = move_object_as(result); + auto chat_info = add_chat(update->chat_id_); + CHECK(chat_info->type != ChatInfo::Type::Unknown); + chat_info->background_custom_emoji_id = update->background_custom_emoji_id_; + break; + } case td_api::updateChatHasProtectedContent::ID: { auto update = move_object_as(result); auto chat_info = add_chat(update->chat_id_); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 03136b0..0c2e42b 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -777,6 +777,7 @@ class Client final : public WebhookActor::Callback { td::string title; int32 message_auto_delete_time = 0; int32 accent_color_id = -1; + int64 background_custom_emoji_id = 0; bool has_protected_content = false; object_ptr photo_info; object_ptr permissions; From cbb0166e7c88f2fca5207972bba3aa97cc0b8911 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 13 Nov 2023 19:51:05 +0300 Subject: [PATCH 09/55] Add "chat_boost" and "removed_chat_boost" updates. --- telegram-bot-api/Client.cpp | 122 ++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 10 +++ 2 files changed, 132 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index df70bf5..7fd8693 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2927,6 +2927,97 @@ class Client::JsonChatJoinRequest final : public td::Jsonable { const Client *client_; }; +class Client::JsonChatBoostSource final : public td::Jsonable { + public: + JsonChatBoostSource(const td_api::ChatBoostSource *boost_source, const Client *client) + : boost_source_(boost_source), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + CHECK(boost_source_ != nullptr); + switch (boost_source_->get_id()) { + case td_api::chatBoostSourcePremium::ID: { + const auto *source = static_cast(boost_source_); + object("source", "premium"); + object("user", JsonUser(source->user_id_, client_)); + break; + } + case td_api::chatBoostSourceGiftCode::ID: { + const auto *source = static_cast(boost_source_); + object("source", "gift_code"); + object("user", JsonUser(source->user_id_, client_)); + break; + } + case td_api::chatBoostSourceGiveaway::ID: { + const auto *source = static_cast(boost_source_); + object("source", "giveaway"); + object("giveaway_message_id", as_client_message_id_unchecked(source->giveaway_message_id_)); + if (source->user_id_ != 0) { + object("user", JsonUser(source->user_id_, client_)); + } else if (source->is_unclaimed_) { + object("is_unclaimed", td::JsonTrue()); + } + break; + } + default: + UNREACHABLE(); + } + } + + private: + const td_api::ChatBoostSource *boost_source_; + const Client *client_; +}; + +class Client::JsonChatBoost final : public td::Jsonable { + public: + JsonChatBoost(const td_api::chatBoost *boost, const Client *client) : boost_(boost), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("boost_id", boost_->id_); + object("add_date", boost_->start_date_); + object("expiration_date", boost_->expiration_date_); + object("source", JsonChatBoostSource(boost_->source_.get(), client_)); + } + + private: + const td_api::chatBoost *boost_; + const Client *client_; +}; + +class Client::JsonChatBoostUpdated final : public td::Jsonable { + public: + JsonChatBoostUpdated(const td_api::updateChatBoost *update, const Client *client) : update_(update), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("chat", JsonChat(update_->chat_id_, false, client_)); + object("boost", JsonChatBoost(update_->boost_.get(), client_)); + } + + private: + const td_api::updateChatBoost *update_; + const Client *client_; +}; + +class Client::JsonChatBoostRemoved final : public td::Jsonable { + public: + JsonChatBoostRemoved(const td_api::updateChatBoost *update, const Client *client) : update_(update), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("chat", JsonChat(update_->chat_id_, false, client_)); + object("boost_id", update_->boost_->id_); + object("remove_date", update_->boost_->start_date_); + object("source", JsonChatBoostSource(update_->boost_->source_.get(), client_)); + } + + private: + const td_api::updateChatBoost *update_; + const Client *client_; +}; + class Client::JsonGameHighScore final : public td::Jsonable { public: JsonGameHighScore(const td_api::gameHighScore *score, const Client *client) : score_(score), client_(client) { @@ -5456,6 +5547,9 @@ void Client::on_update(object_ptr result) { case td_api::updateNewChatJoinRequest::ID: add_update_chat_join_request(move_object_as(result)); break; + case td_api::updateChatBoost::ID: + add_update_chat_boost(move_object_as(result)); + break; case td_api::updateConnectionState::ID: { auto update = move_object_as(result); if (update->state_->get_id() == td_api::connectionStateReady::ID) { @@ -10755,6 +10849,10 @@ td::Slice Client::get_update_type_name(UpdateType update_type) { return td::Slice("chat_member"); case UpdateType::ChatJoinRequest: return td::Slice("chat_join_request"); + case UpdateType::ChatBoostUpdated: + return td::Slice("chat_boost"); + case UpdateType::ChatBoostRemoved: + return td::Slice("removed_chat_boost"); default: UNREACHABLE(); return td::Slice(); @@ -11063,6 +11161,22 @@ void Client::add_update_chat_join_request(object_ptr &&update) { + CHECK(update != nullptr); + auto left_time = update->boost_->start_date_ + 86400 - get_unix_time(); + if (left_time > 0) { + auto webhook_queue_id = update->chat_id_ + (static_cast(7) << 33); + if (update->boost_->expiration_date_ == 0) { + add_update(UpdateType::ChatBoostRemoved, JsonChatBoostRemoved(update.get(), this), left_time, webhook_queue_id); + } else { + add_update(UpdateType::ChatBoostUpdated, JsonChatBoostUpdated(update.get(), this), left_time, webhook_queue_id); + } + } else { + LOG(DEBUG) << "Skip updateChatBoost with date " << update->boost_->start_date_ << ", because current date is " + << get_unix_time(); + } +} + td::int64 Client::choose_added_member_id(const td_api::messageChatAddMembers *message_add_members) const { CHECK(message_add_members != nullptr); for (auto &member_user_id : message_add_members->member_user_ids_) { @@ -11870,6 +11984,14 @@ td::int32 Client::as_client_message_id(int64 message_id) { return result; } +td::int32 Client::as_client_message_id_unchecked(int64 message_id) { + auto result = static_cast(message_id >> 20); + if (as_tdlib_message_id(result) != message_id) { + return 0; + } + return result; +} + td::int64 Client::get_supergroup_chat_id(int64 supergroup_id) { return static_cast(-1000000000000ll) - supergroup_id; } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 0c2e42b..232afc2 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -146,6 +146,10 @@ class Client final : public WebhookActor::Callback { class JsonChatMembers; class JsonChatMemberUpdated; class JsonChatJoinRequest; + class JsonChatBoostSource; + class JsonChatBoost; + class JsonChatBoostUpdated; + class JsonChatBoostRemoved; class JsonForumTopicCreated; class JsonForumTopicEdited; class JsonForumTopicInfo; @@ -913,6 +917,8 @@ class Client final : public WebhookActor::Callback { static int32 as_client_message_id(int64 message_id); + static int32 as_client_message_id_unchecked(int64 message_id); + static int64 get_supergroup_chat_id(int64 supergroup_id); static int64 get_basic_group_chat_id(int64 basic_group_id); @@ -946,6 +952,8 @@ class Client final : public WebhookActor::Callback { void add_update_chat_join_request(object_ptr &&update); + void add_update_chat_boost(object_ptr &&update); + // append only before Size enum class UpdateType : int32 { Message, @@ -964,6 +972,8 @@ class Client final : public WebhookActor::Callback { MyChatMember, ChatMember, ChatJoinRequest, + ChatBoostUpdated, + ChatBoostRemoved, Size }; From f1674d26de4221dc50178dcb9b23ff59ed8b6674 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 13 Nov 2023 20:16:11 +0300 Subject: [PATCH 10/55] Add getUserChatBoosts. --- telegram-bot-api/Client.cpp | 56 +++++++++++++++++++++++++++++++++++-- telegram-bot-api/Client.h | 5 +++- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 7fd8693..ea18d9b 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -292,6 +292,7 @@ bool Client::init_methods() { 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("getuserchatboosts", &Client::process_get_user_chat_boosts_query); methods_.emplace("getstickerset", &Client::process_get_sticker_set_query); methods_.emplace("getcustomemojistickers", &Client::process_get_custom_emoji_stickers_query); methods_.emplace("uploadstickerfile", &Client::process_upload_sticker_file_query); @@ -3018,6 +3019,22 @@ class Client::JsonChatBoostRemoved final : public td::Jsonable { const Client *client_; }; +class Client::JsonChatBoosts final : public td::Jsonable { + public: + JsonChatBoosts(const td_api::foundChatBoosts *chat_boosts, const Client *client) + : chat_boosts_(chat_boosts), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("boosts", td::json_array(chat_boosts_->boosts_, + [client = client_](auto &boost) { return JsonChatBoost(boost.get(), client); })); + } + + private: + const td_api::foundChatBoosts *chat_boosts_; + const Client *client_; +}; + class Client::JsonGameHighScore final : public td::Jsonable { public: JsonGameHighScore(const td_api::gameHighScore *score, const Client *client) : score_(score), client_(client) { @@ -4135,9 +4152,9 @@ class Client::TdOnGetSupergroupMembersCallback final : public TdQueryCallback { PromisedQueryPtr query_; }; -class Client::TdOnGetSupergroupMembersCountCallback final : public TdQueryCallback { +class Client::TdOnGetSupergroupMemberCountCallback final : public TdQueryCallback { public: - explicit TdOnGetSupergroupMembersCountCallback(PromisedQueryPtr query) : query_(std::move(query)) { + explicit TdOnGetSupergroupMemberCountCallback(PromisedQueryPtr query) : query_(std::move(query)) { } void on_result(object_ptr result) final { @@ -4261,6 +4278,26 @@ class Client::TdOnAnswerWebAppQueryCallback final : public TdQueryCallback { PromisedQueryPtr query_; }; +class Client::TdOnGetUserChatBoostsCallback final : public TdQueryCallback { + public: + TdOnGetUserChatBoostsCallback(Client *client, PromisedQueryPtr query) : client_(client), query_(std::move(query)) { + } + + void on_result(object_ptr result) final { + if (result->get_id() == td_api::error::ID) { + return fail_query_with_error(std::move(query_), move_object_as(result)); + } + + CHECK(result->get_id() == td_api::foundChatBoosts::ID); + auto chat_boosts = move_object_as(result); + answer_query(JsonChatBoosts(chat_boosts.get(), client_), std::move(query_)); + } + + private: + Client *client_; + PromisedQueryPtr query_; +}; + class Client::TdOnReturnFileCallback final : public TdQueryCallback { public: TdOnReturnFileCallback(const Client *client, PromisedQueryPtr query) : client_(client), query_(std::move(query)) { @@ -9349,7 +9386,7 @@ td::Status Client::process_get_chat_member_count_query(PromisedQueryPtr &query) } case ChatInfo::Type::Supergroup: return send_request(make_object(chat_info->supergroup_id), - td::make_unique(std::move(query))); + td::make_unique(std::move(query))); case ChatInfo::Type::Unknown: default: UNREACHABLE(); @@ -9611,6 +9648,19 @@ td::Status Client::process_decline_chat_join_request_query(PromisedQueryPtr &que return td::Status::OK(); } +td::Status Client::process_get_user_chat_boosts_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), + td::make_unique(this, std::move(query))); + }); + }); + return td::Status::OK(); +} + td::Status Client::process_get_sticker_set_query(PromisedQueryPtr &query) { auto name = query->arg("name"); if (td::trim(to_lower(name)) == to_lower(GREAT_MINDS_SET_NAME)) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 232afc2..202870c 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -150,6 +150,7 @@ class Client final : public WebhookActor::Callback { class JsonChatBoost; class JsonChatBoostUpdated; class JsonChatBoostRemoved; + class JsonChatBoosts; class JsonForumTopicCreated; class JsonForumTopicEdited; class JsonForumTopicInfo; @@ -204,7 +205,8 @@ class Client final : public WebhookActor::Callback { class TdOnGetChatPinnedMessageToUnpinCallback; class TdOnGetGroupMembersCallback; class TdOnGetSupergroupMembersCallback; - class TdOnGetSupergroupMembersCountCallback; + class TdOnGetSupergroupMemberCountCallback; + class TdOnGetUserChatBoostsCallback; class TdOnCreateInvoiceLinkCallback; class TdOnReplacePrimaryChatInviteLinkCallback; class TdOnGetChatInviteLinkCallback; @@ -611,6 +613,7 @@ class Client final : public WebhookActor::Callback { td::Status process_unban_chat_sender_chat_query(PromisedQueryPtr &query); td::Status process_approve_chat_join_request_query(PromisedQueryPtr &query); td::Status process_decline_chat_join_request_query(PromisedQueryPtr &query); + td::Status process_get_user_chat_boosts_query(PromisedQueryPtr &query); td::Status process_get_sticker_set_query(PromisedQueryPtr &query); td::Status process_get_custom_emoji_stickers_query(PromisedQueryPtr &query); td::Status process_upload_sticker_file_query(PromisedQueryPtr &query); From c39cc1b0ca79bb2bcd63c9f42658482d963462ac Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 13 Nov 2023 21:19:35 +0300 Subject: [PATCH 11/55] Allow to specify link preview options for sent text messages. --- telegram-bot-api/Client.cpp | 66 ++++++++++++++++++++++++++++++++----- telegram-bot-api/Client.h | 13 +++++--- 2 files changed, 66 insertions(+), 13 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index ea18d9b..c8cc11a 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -6267,10 +6267,18 @@ td::Result> Client::get_input_me TRY_RESULT(message_text, object.get_optional_string_field("message_text")); if (!message_text.empty()) { - TRY_RESULT(disable_web_page_preview, object.get_optional_bool_field("disable_web_page_preview")); + object_ptr link_preview_options; + if (object.has_field("link_preview_options")) { + TRY_RESULT(options, object.extract_required_field("link_preview_options", td::JsonValue::Type::Object)); + CHECK(options.type() == td::JsonValue::Type::Object); + TRY_RESULT_ASSIGN(link_preview_options, get_link_preview_options(std::move(options))); + } else { + TRY_RESULT(disable_web_page_preview, object.get_optional_bool_field("disable_web_page_preview")); + link_preview_options = get_link_preview_options(disable_web_page_preview); + } TRY_RESULT(parse_mode, object.get_optional_string_field("parse_mode")); auto entities = object.extract_field("entities"); - TRY_RESULT(input_message_text, get_input_message_text(std::move(message_text), disable_web_page_preview, + TRY_RESULT(input_message_text, get_input_message_text(std::move(message_text), std::move(link_preview_options), std::move(parse_mode), std::move(entities))); return std::move(input_message_text); } @@ -6502,6 +6510,7 @@ td::Result> Client::get_inlin TRY_RESULT(input_message_content_obj, object.extract_optional_field("input_message_content", td::JsonValue::Type::Object)); if (input_message_content_obj.type() == td::JsonValue::Type::Null) { + // legacy TRY_RESULT(message_text, is_input_message_content_required ? object.get_required_string_field("message_text") : object.get_optional_string_field("message_text")); TRY_RESULT(disable_web_page_preview, object.get_optional_bool_field("disable_web_page_preview")); @@ -6509,8 +6518,9 @@ td::Result> Client::get_inlin auto entities = object.extract_field("entities"); if (is_input_message_content_required || !message_text.empty()) { - TRY_RESULT(input_message_text, get_input_message_text(std::move(message_text), disable_web_page_preview, - std::move(parse_mode), std::move(entities))); + TRY_RESULT(input_message_text, + get_input_message_text(std::move(message_text), get_link_preview_options(disable_web_page_preview), + std::move(parse_mode), std::move(entities))); input_message_content = std::move(input_message_text); } } else { @@ -7506,22 +7516,60 @@ td::Result> Client::get_formatted_text return make_object(text, std::move(entities)); } +td_api::object_ptr Client::get_link_preview_options(bool disable_web_page_preview) { + // legacy + if (!disable_web_page_preview) { + return nullptr; + } + return make_object(true, td::string(), false, false, false); +} + +td::Result> Client::get_link_preview_options(const Query *query) { + auto link_preview_options = query->arg("link_preview_options"); + if (link_preview_options.empty()) { + return get_link_preview_options(to_bool(query->arg("disable_web_page_preview"))); + } + + LOG(INFO) << "Parsing JSON object: " << link_preview_options; + auto r_value = json_decode(link_preview_options); + if (r_value.is_error()) { + LOG(INFO) << "Can't parse JSON object: " << r_value.error(); + return td::Status::Error(400, "Can't parse link preview options JSON object"); + } + + return get_link_preview_options(r_value.move_as_ok()); +} + +td::Result> Client::get_link_preview_options(td::JsonValue &&value) { + if (value.type() != td::JsonValue::Type::Object) { + return td::Status::Error(400, "Object expected as link preview options"); + } + auto &object = value.get_object(); + TRY_RESULT(is_disabled, object.get_optional_bool_field("is_disabled")); + TRY_RESULT(url, object.get_optional_string_field("url")); + TRY_RESULT(prefer_small_media, object.get_optional_bool_field("prefer_small_media")); + TRY_RESULT(prefer_large_media, object.get_optional_bool_field("prefer_large_media")); + TRY_RESULT(show_above_text, object.get_optional_bool_field("show_above_text")); + return make_object(is_disabled, url, prefer_small_media, prefer_large_media, + show_above_text); +} + td::Result> Client::get_input_message_text(const Query *query) { - return get_input_message_text(query->arg("text").str(), to_bool(query->arg("disable_web_page_preview")), + TRY_RESULT(link_preview_options, get_link_preview_options(query)); + return get_input_message_text(query->arg("text").str(), std::move(link_preview_options), query->arg("parse_mode").str(), get_input_entities(query, "entities")); } td::Result> Client::get_input_message_text( - td::string text, bool disable_web_page_preview, td::string parse_mode, td::JsonValue &&input_entities) { + td::string text, object_ptr link_preview_options, td::string parse_mode, + td::JsonValue &&input_entities) { if (text.empty()) { return td::Status::Error(400, "Message text is empty"); } TRY_RESULT(formatted_text, get_formatted_text(std::move(text), std::move(parse_mode), std::move(input_entities))); - return make_object( - std::move(formatted_text), - make_object(disable_web_page_preview, td::string(), false, false, false), false); + return make_object(std::move(formatted_text), std::move(link_preview_options), false); } td::Result> Client::get_location(const Query *query) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 202870c..073c8d4 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -464,12 +464,17 @@ class Client final : public WebhookActor::Callback { static td::Result> get_formatted_text(td::string text, td::string parse_mode, td::JsonValue &&input_entities); + static object_ptr get_link_preview_options(bool disable_web_page_preview); + + static td::Result> get_link_preview_options(const Query *query); + + static td::Result> get_link_preview_options(td::JsonValue &&value); + static td::Result> get_input_message_text(const Query *query); - static td::Result> get_input_message_text(td::string text, - bool disable_web_page_preview, - td::string parse_mode, - td::JsonValue &&input_entities); + static td::Result> get_input_message_text( + td::string text, object_ptr link_preview_options, td::string parse_mode, + td::JsonValue &&input_entities); static td::Result> get_location(const Query *query); From 00d351c85c55addaa5c4ea289ddb9c2fcbde009a Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 13 Nov 2023 22:08:07 +0300 Subject: [PATCH 12/55] Add message.link_preview_options. --- telegram-bot-api/Client.cpp | 32 ++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 33 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index c8cc11a..462d2f7 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -939,6 +939,35 @@ class Client::JsonMessages final : public td::Jsonable { const td::vector &messages_; }; +class Client::JsonLinkPreviewOptions final : public td::Jsonable { + public: + JsonLinkPreviewOptions(const td_api::linkPreviewOptions *link_preview_options, const Client *client) + : link_preview_options_(link_preview_options), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + if (link_preview_options_->is_disabled_) { + object("is_disabled", td::JsonTrue()); + } + if (!link_preview_options_->url_.empty()) { + object("url", link_preview_options_->url_); + } + if (link_preview_options_->force_small_media_) { + object("prefer_small_media", td::JsonTrue()); + } + if (link_preview_options_->force_large_media_) { + object("prefer_large_media", td::JsonTrue()); + } + if (link_preview_options_->show_above_text_) { + object("show_above_text", td::JsonTrue()); + } + } + + private: + const td_api::linkPreviewOptions *link_preview_options_; + const Client *client_; +}; + class Client::JsonAnimation final : public td::Jsonable { public: JsonAnimation(const td_api::animation *animation, bool as_document, const Client *client) @@ -2052,6 +2081,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { if (!content->text_->entities_.empty()) { object("entities", JsonVectorEntities(content->text_->entities_, client_)); } + if (content->link_preview_options_ != nullptr) { + object("link_preview_options", JsonLinkPreviewOptions(content->link_preview_options_.get(), client_)); + } break; } case td_api::messageAnimation::ID: { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 073c8d4..28152ef 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -97,6 +97,7 @@ class Client final : public WebhookActor::Callback { class JsonChatInviteLink; class JsonChat; class JsonMessageSender; + class JsonLinkPreviewOptions; class JsonAnimation; class JsonAudio; class JsonDocument; From c44f2c6c3c0a0111b84f886688f40d1107ef36ce Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 13 Nov 2023 22:41:02 +0300 Subject: [PATCH 13/55] Store td_api::MessageOrigin in MessageInfo. --- telegram-bot-api/Client.cpp | 91 ++++++++++++++++--------------------- telegram-bot-api/Client.h | 7 +-- 2 files changed, 39 insertions(+), 59 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 462d2f7..bfbf7b2 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2032,23 +2032,39 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("message_thread_id", as_client_message_id(message_->message_thread_id)); } if (message_->initial_send_date > 0) { - if (message_->initial_sender_user_id != 0) { - object("forward_from", JsonUser(message_->initial_sender_user_id, client_)); - } - if (message_->initial_sender_chat_id != 0) { - object("forward_from_chat", JsonChat(message_->initial_sender_chat_id, false, client_)); - } - if (message_->initial_chat_id != 0) { - object("forward_from_chat", JsonChat(message_->initial_chat_id, false, client_)); - if (message_->initial_message_id != 0) { - object("forward_from_message_id", as_client_message_id(message_->initial_message_id)); + CHECK(message_->forward_origin != nullptr); + switch (message_->forward_origin->get_id()) { + case td_api::messageOriginUser::ID: { + auto forward_info = static_cast(message_->forward_origin.get()); + object("forward_from", JsonUser(forward_info->sender_user_id_, client_)); + break; } - } - if (!message_->initial_author_signature.empty()) { - object("forward_signature", message_->initial_author_signature); - } - if (!message_->initial_sender_name.empty()) { - object("forward_sender_name", message_->initial_sender_name); + case td_api::messageOriginChat::ID: { + auto forward_info = static_cast(message_->forward_origin.get()); + object("forward_from_chat", JsonChat(forward_info->sender_chat_id_, false, client_)); + if (!forward_info->author_signature_.empty()) { + object("forward_signature", forward_info->author_signature_); + } + break; + } + case td_api::messageOriginHiddenUser::ID: { + auto forward_info = static_cast(message_->forward_origin.get()); + if (!forward_info->sender_name_.empty()) { + object("forward_sender_name", forward_info->sender_name_); + } + break; + } + case td_api::messageOriginChannel::ID: { + auto forward_info = static_cast(message_->forward_origin.get()); + object("forward_from_chat", JsonChat(forward_info->chat_id_, false, client_)); + object("forward_from_message_id", as_client_message_id(forward_info->message_id_)); + if (!forward_info->author_signature_.empty()) { + object("forward_signature", forward_info->author_signature_); + } + break; + } + default: + UNREACHABLE(); } if (message_->is_automatic_forward) { object("is_automatic_forward", td::JsonTrue()); @@ -11847,51 +11863,20 @@ Client::FullMessageId Client::add_message(object_ptr &&message, message_info->media_album_id = message->media_album_id_; message_info->via_bot_user_id = message->via_bot_user_id_; - message_info->initial_chat_id = 0; - message_info->initial_sender_user_id = 0; - message_info->initial_sender_chat_id = 0; - message_info->initial_send_date = 0; - message_info->initial_message_id = 0; - message_info->initial_author_signature = td::string(); - message_info->initial_sender_name = td::string(); - message_info->is_automatic_forward = false; if (message->forward_info_ != nullptr) { message_info->initial_send_date = message->forward_info_->date_; - auto origin = std::move(message->forward_info_->origin_); - switch (origin->get_id()) { - case td_api::messageOriginUser::ID: { - auto forward_info = move_object_as(origin); - message_info->initial_sender_user_id = forward_info->sender_user_id_; - break; - } - case td_api::messageOriginChat::ID: { - auto forward_info = move_object_as(origin); - message_info->initial_sender_chat_id = forward_info->sender_chat_id_; - message_info->initial_author_signature = std::move(forward_info->author_signature_); - break; - } - case td_api::messageOriginHiddenUser::ID: { - auto forward_info = move_object_as(origin); - message_info->initial_sender_name = std::move(forward_info->sender_name_); - break; - } - case td_api::messageOriginChannel::ID: { - auto forward_info = move_object_as(origin); - message_info->initial_chat_id = forward_info->chat_id_; - message_info->initial_message_id = forward_info->message_id_; - message_info->initial_author_signature = std::move(forward_info->author_signature_); - break; - } - default: - UNREACHABLE(); - } + message_info->forward_origin = std::move(message->forward_info_->origin_); + auto from_chat_id = message->forward_info_->from_chat_id_; message_info->is_automatic_forward = from_chat_id != 0 && from_chat_id != chat_id && message->forward_info_->from_message_id_ != 0 && get_chat_type(chat_id) == ChatType::Supergroup && get_chat_type(from_chat_id) == ChatType::Channel; } else if (message->import_info_ != nullptr) { message_info->initial_send_date = message->import_info_->date_; - message_info->initial_sender_name = std::move(message->import_info_->sender_name_); + message_info->forward_origin = make_object(message->import_info_->sender_name_); + } else { + message_info->initial_send_date = 0; + message_info->forward_origin = nullptr; } CHECK(message->sender_id_ != nullptr); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 28152ef..6abddec 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -817,13 +817,8 @@ class Client final : public WebhookActor::Callback { int64 message_thread_id = 0; int32 date = 0; int32 edit_date = 0; - int64 initial_chat_id = 0; - int64 initial_sender_user_id = 0; - int64 initial_sender_chat_id = 0; int32 initial_send_date = 0; - int64 initial_message_id = 0; - td::string initial_author_signature; - td::string initial_sender_name; + object_ptr forward_origin; td::string author_signature; object_ptr reply_to_message; int64 media_album_id = 0; From c729e35ddbd9216dc79d21adf1ec2df21be565f0 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 13 Nov 2023 23:17:15 +0300 Subject: [PATCH 14/55] Add Message.forward_origin. --- telegram-bot-api/Client.cpp | 61 +++++++++++++++++++++++++++++++++++-- telegram-bot-api/Client.h | 1 + 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index bfbf7b2..73fc578 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -924,6 +924,59 @@ class Client::JsonMessageSender final : public td::Jsonable { const Client *client_; }; +class Client::JsonMessageOrigin final : public td::Jsonable { + public: + JsonMessageOrigin(const td_api::MessageOrigin *message_origin, int32 initial_send_date, const Client *client) + : message_origin_(message_origin), initial_send_date_(initial_send_date), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + switch (message_origin_->get_id()) { + case td_api::messageOriginUser::ID: { + auto origin = static_cast(message_origin_); + object("type", "user"); + object("sender_user", JsonUser(origin->sender_user_id_, client_)); + break; + } + case td_api::messageOriginChat::ID: { + auto origin = static_cast(message_origin_); + object("type", "chat"); + object("sender_chat", JsonChat(origin->sender_chat_id_, false, client_)); + if (!origin->author_signature_.empty()) { + object("author_signature", origin->author_signature_); + } + break; + } + case td_api::messageOriginHiddenUser::ID: { + auto origin = static_cast(message_origin_); + object("type", "hidden_user"); + if (!origin->sender_name_.empty()) { + object("sender_user_name", origin->sender_name_); + } + break; + } + case td_api::messageOriginChannel::ID: { + auto origin = static_cast(message_origin_); + object("type", "channel"); + object("chat", JsonChat(origin->chat_id_, false, client_)); + object("message_id", as_client_message_id(origin->message_id_)); + if (!origin->author_signature_.empty()) { + object("author_signature", origin->author_signature_); + } + break; + } + default: + UNREACHABLE(); + } + object("date", initial_send_date_); + } + + private: + const td_api::MessageOrigin *message_origin_; + int32 initial_send_date_; + const Client *client_; +}; + class Client::JsonMessages final : public td::Jsonable { public: explicit JsonMessages(const td::vector &messages) : messages_(messages) { @@ -2033,6 +2086,11 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { } if (message_->initial_send_date > 0) { CHECK(message_->forward_origin != nullptr); + object("forward_origin", JsonMessageOrigin(message_->forward_origin.get(), message_->initial_send_date, client_)); + if (message_->is_automatic_forward) { + object("is_automatic_forward", td::JsonTrue()); + } + switch (message_->forward_origin->get_id()) { case td_api::messageOriginUser::ID: { auto forward_info = static_cast(message_->forward_origin.get()); @@ -2066,9 +2124,6 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { default: UNREACHABLE(); } - if (message_->is_automatic_forward) { - object("is_automatic_forward", td::JsonTrue()); - } object("forward_date", message_->initial_send_date); } if (need_reply_) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 6abddec..7850e36 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -97,6 +97,7 @@ class Client final : public WebhookActor::Callback { class JsonChatInviteLink; class JsonChat; class JsonMessageSender; + class JsonMessageOrigin; class JsonLinkPreviewOptions; class JsonAnimation; class JsonAudio; From 52171bd90cdba187ca40297a131b4d9571883dbc Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 14 Nov 2023 12:56:32 +0300 Subject: [PATCH 15/55] Add Message.external_reply. --- telegram-bot-api/Client.cpp | 132 +++++++++++++++++++++++++++++++++++- telegram-bot-api/Client.h | 1 + 2 files changed, 132 insertions(+), 1 deletion(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 73fc578..32841e4 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2063,6 +2063,136 @@ class Client::JsonReplyMarkup final : public td::Jsonable { const td_api::ReplyMarkup *reply_markup_; }; +class Client::JsonExternalReplyInfo final : public td::Jsonable { + public: + JsonExternalReplyInfo(const td_api::messageReplyToMessage *reply, const Client *client) + : reply_(reply), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("origin", JsonMessageOrigin(reply_->origin_.get(), reply_->origin_send_date_, client_)); + if (reply_->chat_id_ != 0) { + object("chat", JsonChat(reply_->chat_id_, false, client_)); + if (reply_->message_id_ != 0) { + object("message_id", as_client_message_id(reply_->message_id_)); + } + } + if (reply_->content_ != nullptr) { + switch (reply_->content_->get_id()) { + case td_api::messageText::ID: { + auto content = static_cast(reply_->content_.get()); + if (content->link_preview_options_ != nullptr) { + object("link_preview_options", JsonLinkPreviewOptions(content->link_preview_options_.get(), client_)); + } + break; + } + case td_api::messageAnimation::ID: { + auto content = static_cast(reply_->content_.get()); + object("animation", JsonAnimation(content->animation_.get(), false, client_)); + add_media_spoiler(object, content->has_spoiler_); + break; + } + case td_api::messageAudio::ID: { + auto content = static_cast(reply_->content_.get()); + object("audio", JsonAudio(content->audio_.get(), client_)); + break; + } + case td_api::messageDocument::ID: { + auto content = static_cast(reply_->content_.get()); + object("document", JsonDocument(content->document_.get(), client_)); + break; + } + case td_api::messagePhoto::ID: { + auto content = static_cast(reply_->content_.get()); + CHECK(content->photo_ != nullptr); + object("photo", JsonPhoto(content->photo_.get(), client_)); + add_media_spoiler(object, content->has_spoiler_); + break; + } + case td_api::messageSticker::ID: { + auto content = static_cast(reply_->content_.get()); + object("sticker", JsonSticker(content->sticker_.get(), client_)); + break; + } + case td_api::messageVideo::ID: { + auto content = static_cast(reply_->content_.get()); + object("video", JsonVideo(content->video_.get(), client_)); + add_media_spoiler(object, content->has_spoiler_); + break; + } + case td_api::messageVideoNote::ID: { + auto content = static_cast(reply_->content_.get()); + object("video_note", JsonVideoNote(content->video_note_.get(), client_)); + break; + } + case td_api::messageVoiceNote::ID: { + auto content = static_cast(reply_->content_.get()); + object("voice", JsonVoiceNote(content->voice_note_.get(), client_)); + break; + } + case td_api::messageContact::ID: { + auto content = static_cast(reply_->content_.get()); + object("contact", JsonContact(content->contact_.get())); + break; + } + case td_api::messageDice::ID: { + auto content = static_cast(reply_->content_.get()); + object("dice", JsonDice(content->emoji_, content->value_)); + break; + } + case td_api::messageGame::ID: { + auto content = static_cast(reply_->content_.get()); + object("game", JsonGame(content->game_.get(), client_)); + break; + } + case td_api::messageInvoice::ID: { + auto content = static_cast(reply_->content_.get()); + object("invoice", JsonInvoice(content)); + break; + } + case td_api::messageLocation::ID: { + auto content = static_cast(reply_->content_.get()); + object("location", JsonLocation(content->location_.get(), content->expires_in_, content->live_period_, + content->heading_, content->proximity_alert_radius_)); + break; + } + case td_api::messageVenue::ID: { + auto content = static_cast(reply_->content_.get()); + object("venue", JsonVenue(content->venue_.get())); + break; + } + case td_api::messagePoll::ID: { + auto content = static_cast(reply_->content_.get()); + object("poll", JsonPoll(content->poll_.get(), client_)); + break; + } + case td_api::messageUnsupported::ID: + break; + case td_api::messagePremiumGiveaway::ID: { + auto content = static_cast(reply_->content_.get()); + object("giveaway", JsonGiveaway(content, client_)); + break; + } + case td_api::messageStory::ID: + object("story", JsonEmptyObject()); + break; + default: + LOG(ERROR) << "Receive external reply with " << to_string(reply_->content_); + } + } + } + + private: + const td_api::messageReplyToMessage *reply_; + const Client *client_; + + void add_media_spoiler(td::JsonObjectScope &object, bool has_spoiler) const { + if (has_spoiler) { + object("has_media_spoiler", td::JsonTrue()); + } + } +}; + void Client::JsonMessage::store(td::JsonValueScope *scope) const { CHECK(message_ != nullptr); auto object = scope->enter_object(); @@ -2140,7 +2270,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { } } if (message_->reply_to_message != nullptr && message_->reply_to_message->origin_ != nullptr) { - // external reply + object("external_reply", JsonExternalReplyInfo(message_->reply_to_message.get(), client_)); } if (message_->media_album_id != 0) { object("media_group_id", td::to_string(message_->media_album_id)); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 7850e36..ad2384c 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -98,6 +98,7 @@ class Client final : public WebhookActor::Callback { class JsonChat; class JsonMessageSender; class JsonMessageOrigin; + class JsonExternalReplyInfo; class JsonLinkPreviewOptions; class JsonAnimation; class JsonAudio; From 096f0660248cf9b07837422e7066f2c0744a12a6 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 14 Nov 2023 13:00:27 +0300 Subject: [PATCH 16/55] Add Message.quote and Message.quote_entities. --- telegram-bot-api/Client.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 32841e4..121f971 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2272,6 +2272,12 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { if (message_->reply_to_message != nullptr && message_->reply_to_message->origin_ != nullptr) { object("external_reply", JsonExternalReplyInfo(message_->reply_to_message.get(), client_)); } + if (message_->reply_to_message != nullptr && message_->reply_to_message->quote_ != nullptr) { + object("quote", message_->reply_to_message->quote_->text_); + if (!message_->reply_to_message->quote_->entities_.empty()) { + object("quote_entities", JsonVectorEntities(message_->reply_to_message->quote_->entities_, client_)); + } + } if (message_->media_album_id != 0) { object("media_group_id", td::to_string(message_->media_album_id)); } From 76c108bf3c7af07d92255c6495b868d1230e3a8e Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 14 Nov 2023 13:07:14 +0300 Subject: [PATCH 17/55] Simplify JsonChat usage. --- telegram-bot-api/Client.cpp | 41 ++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 121f971..f0e0108 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -690,8 +690,8 @@ class Client::JsonMessage final : public td::Jsonable { class Client::JsonChat final : public td::Jsonable { public: - JsonChat(int64 chat_id, bool is_full, const Client *client, int64 pinned_message_id = -1) - : chat_id_(chat_id), is_full_(is_full), client_(client), pinned_message_id_(pinned_message_id) { + JsonChat(int64 chat_id, const Client *client, bool is_full = false, int64 pinned_message_id = -1) + : chat_id_(chat_id), client_(client), is_full_(is_full), pinned_message_id_(pinned_message_id) { } void store(td::JsonValueScope *scope) const { auto chat_info = client_->get_chat(chat_id_); @@ -891,8 +891,8 @@ class Client::JsonChat final : public td::Jsonable { private: int64 chat_id_; - bool is_full_; const Client *client_; + bool is_full_; int64 pinned_message_id_; }; @@ -911,7 +911,7 @@ class Client::JsonMessageSender final : public td::Jsonable { } case td_api::messageSenderChat::ID: { auto sender_chat_id = static_cast(sender_id_)->chat_id_; - JsonChat(sender_chat_id, false, client_).store(scope); + JsonChat(sender_chat_id, client_).store(scope); break; } default: @@ -941,7 +941,7 @@ class Client::JsonMessageOrigin final : public td::Jsonable { case td_api::messageOriginChat::ID: { auto origin = static_cast(message_origin_); object("type", "chat"); - object("sender_chat", JsonChat(origin->sender_chat_id_, false, client_)); + object("sender_chat", JsonChat(origin->sender_chat_id_, client_)); if (!origin->author_signature_.empty()) { object("author_signature", origin->author_signature_); } @@ -958,7 +958,7 @@ class Client::JsonMessageOrigin final : public td::Jsonable { case td_api::messageOriginChannel::ID: { auto origin = static_cast(message_origin_); object("type", "channel"); - object("chat", JsonChat(origin->chat_id_, false, client_)); + object("chat", JsonChat(origin->chat_id_, client_)); object("message_id", as_client_message_id(origin->message_id_)); if (!origin->author_signature_.empty()) { object("author_signature", origin->author_signature_); @@ -1515,7 +1515,7 @@ class Client::JsonPollAnswer final : public td::Jsonable { case td_api::messageSenderChat::ID: { auto voter_chat_id = static_cast(poll_answer_->voter_id_.get())->chat_id_; object("user", JsonUser(client_->channel_bot_user_id_, client_)); - object("voter_chat", JsonChat(voter_chat_id, false, client_)); + object("voter_chat", JsonChat(voter_chat_id, client_)); break; } default: @@ -1917,8 +1917,7 @@ class Client::JsonGiveaway final : public td::Jsonable { for (auto chat_id : giveaway_->parameters_->additional_chat_ids_) { chat_ids.push_back(chat_id); } - object("chats", - td::json_array(chat_ids, [client = client_](auto &chat_id) { return JsonChat(chat_id, false, client); })); + object("chats", td::json_array(chat_ids, [client = client_](auto &chat_id) { return JsonChat(chat_id, client); })); object("winners_selection_date", giveaway_->parameters_->winners_selection_date_); object("winner_count", giveaway_->winner_count_); if (giveaway_->parameters_->only_new_members_) { @@ -2072,7 +2071,7 @@ class Client::JsonExternalReplyInfo final : public td::Jsonable { auto object = scope->enter_object(); object("origin", JsonMessageOrigin(reply_->origin_.get(), reply_->origin_send_date_, client_)); if (reply_->chat_id_ != 0) { - object("chat", JsonChat(reply_->chat_id_, false, client_)); + object("chat", JsonChat(reply_->chat_id_, client_)); if (reply_->message_id_ != 0) { object("message_id", as_client_message_id(reply_->message_id_)); } @@ -2204,9 +2203,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("author_signature", message_->author_signature); } if (message_->sender_chat_id != 0) { - object("sender_chat", JsonChat(message_->sender_chat_id, false, client_)); + object("sender_chat", JsonChat(message_->sender_chat_id, client_)); } - object("chat", JsonChat(message_->chat_id, false, client_)); + object("chat", JsonChat(message_->chat_id, client_)); object("date", message_->date); if (message_->edit_date > 0) { object("edit_date", message_->edit_date); @@ -2229,7 +2228,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { } case td_api::messageOriginChat::ID: { auto forward_info = static_cast(message_->forward_origin.get()); - object("forward_from_chat", JsonChat(forward_info->sender_chat_id_, false, client_)); + object("forward_from_chat", JsonChat(forward_info->sender_chat_id_, client_)); if (!forward_info->author_signature_.empty()) { object("forward_signature", forward_info->author_signature_); } @@ -2244,7 +2243,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { } case td_api::messageOriginChannel::ID: { auto forward_info = static_cast(message_->forward_origin.get()); - object("forward_from_chat", JsonChat(forward_info->chat_id_, false, client_)); + object("forward_from_chat", JsonChat(forward_info->chat_id_, client_)); object("forward_from_message_id", as_client_message_id(forward_info->message_id_)); if (!forward_info->author_signature_.empty()) { object("forward_signature", forward_info->author_signature_); @@ -2646,7 +2645,7 @@ class Client::JsonDeletedMessage final : public td::Jsonable { void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); object("message_id", as_client_message_id(message_id_)); - object("chat", JsonChat(chat_id_, false, client_)); + object("chat", JsonChat(chat_id_, client_)); object("date", 0); } @@ -3124,7 +3123,7 @@ class Client::JsonChatMemberUpdated final : public td::Jsonable { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("chat", JsonChat(update_->chat_id_, false, client_)); + object("chat", JsonChat(update_->chat_id_, client_)); object("from", JsonUser(update_->actor_user_id_, client_)); object("date", update_->date_); auto chat_type = client_->get_chat_type(update_->chat_id_); @@ -3150,7 +3149,7 @@ class Client::JsonChatJoinRequest final : public td::Jsonable { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("chat", JsonChat(update_->chat_id_, false, client_)); + object("chat", JsonChat(update_->chat_id_, client_)); object("from", JsonUser(update_->request_->user_id_, client_)); object("user_chat_id", update_->user_chat_id_); object("date", update_->request_->date_); @@ -3232,7 +3231,7 @@ class Client::JsonChatBoostUpdated final : public td::Jsonable { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("chat", JsonChat(update_->chat_id_, false, client_)); + object("chat", JsonChat(update_->chat_id_, client_)); object("boost", JsonChatBoost(update_->boost_.get(), client_)); } @@ -3247,7 +3246,7 @@ class Client::JsonChatBoostRemoved final : public td::Jsonable { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("chat", JsonChat(update_->chat_id_, false, client_)); + object("chat", JsonChat(update_->chat_id_, client_)); object("boost_id", update_->boost_->id_); object("remove_date", update_->boost_->start_date_); object("source", JsonChatBoostSource(update_->boost_->source_.get(), client_)); @@ -4089,7 +4088,7 @@ class Client::TdOnGetChatStickerSetCallback final : public TdQueryCallback { client_->on_get_sticker_set_name(sticker_set->id_, sticker_set->name_); } - answer_query(JsonChat(chat_id_, true, client_, pinned_message_id_), std::move(query_)); + answer_query(JsonChat(chat_id_, client_, true, pinned_message_id_), std::move(query_)); } private: @@ -4136,7 +4135,7 @@ class Client::TdOnGetChatPinnedMessageCallback final : public TdQueryCallback { } } - answer_query(JsonChat(chat_id_, true, client_, pinned_message_id), std::move(query_)); + answer_query(JsonChat(chat_id_, client_, true, pinned_message_id), std::move(query_)); } private: From 095511b4ebd3181b16f8421679a4962b7a0f16d3 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 14 Nov 2023 18:10:00 +0300 Subject: [PATCH 18/55] Add Client::check_reply_parameters. --- telegram-bot-api/Client.cpp | 119 +++++++++++++++++------------------- telegram-bot-api/Client.h | 4 +- 2 files changed, 58 insertions(+), 65 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index f0e0108..efe7778 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -5184,27 +5184,33 @@ void Client::check_message(td::Slice chat_id_str, int64 message_id, bool allow_e } 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)); - } +void Client::check_reply_parameters(td::Slice chat_id_str, int64 reply_to_message_id, bool allow_sending_without_reply, + int64 message_thread_id, PromisedQueryPtr query, OnSuccess on_success) { + check_message(chat_id_str, reply_to_message_id, reply_to_message_id <= 0 || allow_sending_without_reply, + AccessRights::Write, "message to reply", std::move(query), + [this, message_thread_id, on_success = std::move(on_success)](int64 chat_id, int64 reply_to_message_id, + PromisedQueryPtr query) mutable { + 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, true); - 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)); - } + if (reply_to_message_id != 0) { + const MessageInfo *message_info = get_message(chat_id, reply_to_message_id, true); + 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))); + 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 @@ -8842,33 +8848,26 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { [this, chat_id = chat_id.str(), message_thread_id, reply_to_message_id, allow_sending_without_reply, disable_notification, protect_content, input_message_contents = std::move(input_message_contents)]( object_ptr reply_markup, PromisedQueryPtr query) mutable { - auto on_success = [this, message_thread_id, disable_notification, protect_content, + auto on_success = [this, disable_notification, protect_content, input_message_contents = std::move(input_message_contents), - reply_markup = std::move(reply_markup)](int64 chat_id, int64 reply_to_message_id, + reply_markup = std::move(reply_markup)](int64 chat_id, int64 message_thread_id, + int64 reply_to_message_id, PromisedQueryPtr query) mutable { - 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 &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 = input_message_contents.size(); - count += static_cast(message_count); + 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 = input_message_contents.size(); + count += static_cast(message_count); - send_request( - make_object( - chat_id, message_thread_id, get_input_message_reply_to(reply_to_message_id), - get_message_send_options(disable_notification, protect_content), std::move(input_message_contents)), - td::make_unique(this, chat_id, message_count, std::move(query))); - }; - check_message_thread(chat_id, message_thread_id, reply_to_message_id, std::move(query), - std::move(on_message_thread_checked)); + send_request( + make_object( + chat_id, message_thread_id, get_input_message_reply_to(reply_to_message_id), + get_message_send_options(disable_notification, protect_content), std::move(input_message_contents)), + td::make_unique(this, chat_id, message_count, std::move(query))); }; - check_message(chat_id, reply_to_message_id, reply_to_message_id <= 0 || allow_sending_without_reply, - AccessRights::Write, "message to reply", std::move(query), std::move(on_success)); + check_reply_parameters(chat_id, reply_to_message_id, allow_sending_without_reply, message_thread_id, + std::move(query), std::move(on_success)); }); return td::Status::OK(); } @@ -10596,31 +10595,25 @@ void Client::do_send_message(object_ptr input_messa [this, chat_id = chat_id.str(), message_thread_id, reply_to_message_id, allow_sending_without_reply, disable_notification, protect_content, input_message_content = std::move(input_message_content)]( object_ptr reply_markup, PromisedQueryPtr query) mutable { - auto on_success = [this, message_thread_id, disable_notification, protect_content, + auto on_success = [this, disable_notification, protect_content, input_message_content = std::move(input_message_content), - reply_markup = std::move(reply_markup)](int64 chat_id, int64 reply_to_message_id, + reply_markup = std::move(reply_markup)](int64 chat_id, int64 message_thread_id, + int64 reply_to_message_id, PromisedQueryPtr query) mutable { - 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 &count = yet_unsent_message_count_[chat_id]; - if (count >= MAX_CONCURRENTLY_SENT_CHAT_MESSAGES) { - return fail_query_flood_limit_exceeded(std::move(query)); - } - count++; + auto &count = yet_unsent_message_count_[chat_id]; + if (count >= MAX_CONCURRENTLY_SENT_CHAT_MESSAGES) { + return fail_query_flood_limit_exceeded(std::move(query)); + } + count++; - send_request(make_object( - chat_id, message_thread_id, get_input_message_reply_to(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, chat_id, std::move(query))); - }; - check_message_thread(chat_id, message_thread_id, reply_to_message_id, std::move(query), - std::move(on_message_thread_checked)); + send_request(make_object(chat_id, message_thread_id, + get_input_message_reply_to(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, chat_id, std::move(query))); }; - check_message(chat_id, reply_to_message_id, reply_to_message_id <= 0 || allow_sending_without_reply, - AccessRights::Write, "message to reply", std::move(query), std::move(on_success)); + check_reply_parameters(chat_id, reply_to_message_id, allow_sending_without_reply, message_thread_id, + std::move(query), std::move(on_success)); }); } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index ad2384c..af09528 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -304,8 +304,8 @@ class Client final : public WebhookActor::Callback { td::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); + void check_reply_parameters(td::Slice chat_id_str, int64 reply_to_message_id, bool allow_sending_without_reply, + int64 message_thread_id, PromisedQueryPtr query, OnSuccess on_success); template void resolve_sticker_set(const td::string &sticker_set_name, PromisedQueryPtr query, OnSuccess on_success); From 9f5b2fa5371536070c90a7c5e26d789650635ebe Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 14 Nov 2023 18:55:55 +0300 Subject: [PATCH 19/55] Add class ReplyParameters and fields "reply_parameters". --- telegram-bot-api/Client.cpp | 106 +++++++++++++++++++++++++----------- telegram-bot-api/Client.h | 20 ++++++- 2 files changed, 92 insertions(+), 34 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index efe7778..6998139 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3851,12 +3851,12 @@ class Client::TdOnCheckMessageCallback final : public TdQueryCallback { 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) + TdOnCheckMessageThreadCallback(Client *client, int64 chat_id, int64 message_thread_id, + CheckedReplyParameters reply_parameters, 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) + , reply_parameters_(std::move(reply_parameters)) , query_(std::move(query)) , on_success_(std::move(on_success)) { } @@ -3885,14 +3885,14 @@ class Client::TdOnCheckMessageThreadCallback final : public TdQueryCallback { "Message thread is not a forum topic thread"); } - on_success_(chat_id_, message_thread_id_, reply_to_message_id_, std::move(query_)); + on_success_(chat_id_, message_thread_id_, std::move(reply_parameters_), std::move(query_)); } private: Client *client_; int64 chat_id_; int64 message_thread_id_; - int64 reply_to_message_id_; + CheckedReplyParameters reply_parameters_; PromisedQueryPtr query_; OnSuccess on_success_; }; @@ -5184,14 +5184,18 @@ void Client::check_message(td::Slice chat_id_str, int64 message_id, bool allow_e } template -void Client::check_reply_parameters(td::Slice chat_id_str, int64 reply_to_message_id, bool allow_sending_without_reply, +void Client::check_reply_parameters(td::Slice chat_id_str, InputReplyParameters &&reply_parameters, int64 message_thread_id, PromisedQueryPtr query, OnSuccess on_success) { - check_message(chat_id_str, reply_to_message_id, reply_to_message_id <= 0 || allow_sending_without_reply, + check_message(chat_id_str, reply_parameters.reply_to_message_id, + reply_parameters.reply_to_message_id <= 0 || reply_parameters.allow_sending_without_reply, AccessRights::Write, "message to reply", std::move(query), [this, message_thread_id, on_success = std::move(on_success)](int64 chat_id, int64 reply_to_message_id, PromisedQueryPtr query) mutable { + CheckedReplyParameters reply_parameters; + reply_parameters.reply_to_message_id = reply_to_message_id; + if (message_thread_id <= 0) { - return on_success(chat_id, 0, reply_to_message_id, std::move(query)); + return on_success(chat_id, 0, std::move(reply_parameters), std::move(query)); } if (reply_to_message_id != 0) { @@ -5203,12 +5207,12 @@ void Client::check_reply_parameters(td::Slice chat_id_str, int64 reply_to_messag } } if (reply_to_message_id == message_thread_id) { - return on_success(chat_id, message_thread_id, reply_to_message_id, std::move(query)); + return on_success(chat_id, message_thread_id, std::move(reply_parameters), 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), + this, chat_id, message_thread_id, std::move(reply_parameters), std::move(query), std::move(on_success))); }); } @@ -5975,13 +5979,51 @@ bool Client::to_bool(td::MutableSlice value) { return value == "true" || value == "yes" || value == "1"; } -td_api::object_ptr Client::get_input_message_reply_to(int64 reply_to_message_id) { - if (reply_to_message_id > 0) { - return make_object(0, reply_to_message_id, nullptr); +td_api::object_ptr Client::get_input_message_reply_to( + const CheckedReplyParameters &reply_parameters) { + if (reply_parameters.reply_to_message_id > 0) { + return make_object(0, reply_parameters.reply_to_message_id, nullptr); } return nullptr; } +td::Result Client::get_reply_parameters(const Query *query) { + if (!query->has_arg("reply_parameters")) { + InputReplyParameters result; + result.reply_to_message_id = get_message_id(query, "reply_to_message_id"); + result.allow_sending_without_reply = to_bool(query->arg("allow_sending_without_reply")); + return std::move(result); + } + + auto reply_parameters = query->arg("reply_parameters"); + if (reply_parameters.empty()) { + return InputReplyParameters(); + } + + LOG(INFO) << "Parsing JSON object: " << reply_parameters; + auto r_value = json_decode(reply_parameters); + if (r_value.is_error()) { + LOG(INFO) << "Can't parse JSON object: " << r_value.error(); + return td::Status::Error(400, "Can't parse reply parameters JSON object"); + } + + return get_reply_parameters(r_value.move_as_ok()); +} + +td::Result Client::get_reply_parameters(td::JsonValue &&value) { + if (value.type() != td::JsonValue::Type::Object) { + return td::Status::Error(400, "Object expected as reply parameters"); + } + auto &object = value.get_object(); + TRY_RESULT(message_id, object.get_required_int_field("message_id")); + TRY_RESULT(allow_sending_without_reply, object.get_optional_bool_field("allow_sending_without_reply")); + + InputReplyParameters result; + result.reply_to_message_id = as_tdlib_message_id(td::max(message_id, 0)); + result.allow_sending_without_reply = allow_sending_without_reply; + return std::move(result); +} + td::Result> Client::get_keyboard_button(td::JsonValue &button) { if (button.type() == td::JsonValue::Type::Object) { auto &object = button.get_object(); @@ -8835,8 +8877,7 @@ td::Status Client::process_forward_message_query(PromisedQueryPtr &query) { 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"); - auto reply_to_message_id = get_message_id(query.get(), "reply_to_message_id"); - auto allow_sending_without_reply = to_bool(query->arg("allow_sending_without_reply")); + TRY_RESULT(reply_parameters, get_reply_parameters(query.get())); auto disable_notification = to_bool(query->arg("disable_notification")); auto protect_content = to_bool(query->arg("protect_content")); // TRY_RESULT(reply_markup, get_reply_markup(query.get(), bot_user_ids_)); @@ -8845,13 +8886,13 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, chat_id = chat_id.str(), message_thread_id, reply_to_message_id, allow_sending_without_reply, + [this, chat_id = chat_id.str(), message_thread_id, reply_parameters = std::move(reply_parameters), disable_notification, protect_content, input_message_contents = std::move(input_message_contents)]( object_ptr reply_markup, PromisedQueryPtr query) mutable { auto on_success = [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, + CheckedReplyParameters reply_parameters, PromisedQueryPtr query) mutable { auto &count = yet_unsent_message_count_[chat_id]; if (count >= MAX_CONCURRENTLY_SENT_CHAT_MESSAGES) { @@ -8862,12 +8903,12 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { send_request( make_object( - chat_id, message_thread_id, get_input_message_reply_to(reply_to_message_id), + chat_id, message_thread_id, get_input_message_reply_to(reply_parameters), get_message_send_options(disable_notification, protect_content), std::move(input_message_contents)), td::make_unique(this, chat_id, message_count, std::move(query))); }; - check_reply_parameters(chat_id, reply_to_message_id, allow_sending_without_reply, message_thread_id, - std::move(query), std::move(on_success)); + check_reply_parameters(chat_id, std::move(reply_parameters), message_thread_id, std::move(query), + std::move(on_success)); }); return td::Status::OK(); } @@ -10580,8 +10621,11 @@ void Client::do_send_message(object_ptr input_messa bool force) { auto chat_id = query->arg("chat_id"); auto message_thread_id = get_message_id(query.get(), "message_thread_id"); - auto reply_to_message_id = get_message_id(query.get(), "reply_to_message_id"); - auto allow_sending_without_reply = to_bool(query->arg("allow_sending_without_reply")); + auto r_reply_parameters = get_reply_parameters(query.get()); + if (r_reply_parameters.is_error()) { + return fail_query_with_error(std::move(query), 400, r_reply_parameters.error().message()); + } + auto reply_parameters = r_reply_parameters.move_as_ok(); auto disable_notification = to_bool(query->arg("disable_notification")); auto protect_content = to_bool(query->arg("protect_content")); auto r_reply_markup = get_reply_markup(query.get(), bot_user_ids_); @@ -10592,13 +10636,13 @@ void Client::do_send_message(object_ptr input_messa resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, chat_id = chat_id.str(), message_thread_id, reply_to_message_id, allow_sending_without_reply, + [this, chat_id = chat_id.str(), message_thread_id, reply_parameters = std::move(reply_parameters), disable_notification, protect_content, input_message_content = std::move(input_message_content)]( object_ptr reply_markup, PromisedQueryPtr query) mutable { auto on_success = [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, + CheckedReplyParameters reply_parameters, PromisedQueryPtr query) mutable { auto &count = yet_unsent_message_count_[chat_id]; if (count >= MAX_CONCURRENTLY_SENT_CHAT_MESSAGES) { @@ -10606,14 +10650,14 @@ void Client::do_send_message(object_ptr input_messa } count++; - send_request(make_object(chat_id, message_thread_id, - get_input_message_reply_to(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, chat_id, std::move(query))); + send_request( + make_object(chat_id, message_thread_id, get_input_message_reply_to(reply_parameters), + get_message_send_options(disable_notification, protect_content), + std::move(reply_markup), std::move(input_message_content)), + td::make_unique(this, chat_id, std::move(query))); }; - check_reply_parameters(chat_id, reply_to_message_id, allow_sending_without_reply, message_thread_id, - std::move(query), std::move(on_success)); + check_reply_parameters(chat_id, std::move(reply_parameters), message_thread_id, std::move(query), + std::move(on_success)); }); } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index af09528..658ff11 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -245,6 +245,15 @@ class Client final : public WebhookActor::Callback { virtual ~TdQueryCallback() = default; }; + struct InputReplyParameters { + int64 reply_to_message_id = 0; + bool allow_sending_without_reply = false; + }; + + struct CheckedReplyParameters { + int64 reply_to_message_id = 0; + }; + struct UserInfo; struct ChatInfo; struct BotCommandScope; @@ -304,8 +313,8 @@ class Client final : public WebhookActor::Callback { td::Slice message_type, PromisedQueryPtr query, OnSuccess on_success); template - void check_reply_parameters(td::Slice chat_id_str, int64 reply_to_message_id, bool allow_sending_without_reply, - int64 message_thread_id, PromisedQueryPtr query, OnSuccess on_success); + void check_reply_parameters(td::Slice chat_id_str, InputReplyParameters &&reply_parameters, int64 message_thread_id, + PromisedQueryPtr query, OnSuccess on_success); template void resolve_sticker_set(const td::string &sticker_set_name, PromisedQueryPtr query, OnSuccess on_success); @@ -341,7 +350,12 @@ class Client final : public WebhookActor::Callback { static bool to_bool(td::MutableSlice value); - static object_ptr get_input_message_reply_to(int64 reply_to_message_id); + static object_ptr get_input_message_reply_to( + const CheckedReplyParameters &reply_parameters); + + static td::Result get_reply_parameters(const Query *query); + + static td::Result get_reply_parameters(td::JsonValue &&value); static td::Result> get_keyboard_button(td::JsonValue &button); From fcb1814a0c601e6f9fe234e0c46f92babe10c2d8 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 14 Nov 2023 19:22:17 +0300 Subject: [PATCH 20/55] Improve error message. --- telegram-bot-api/Client.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 6998139..d23930f 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -11774,7 +11774,9 @@ void Client::drop_internal_reply_to_message_in_another_chat(object_ptrchat_id_; if (reply_in_chat_id != message->chat_id_ && reply_to->origin_ == nullptr) { LOG(ERROR) << "Drop reply to message " << message->id_ << " in chat " << message->chat_id_ - << " from another chat " << reply_in_chat_id; + << " from another chat " << reply_in_chat_id << " sent at " << message->date_ + << " and originally sent at " + << (message->forward_info_ != nullptr ? message->forward_info_->date_ : -1); message->reply_to_ = nullptr; } } From 1333e3d2ea0c361e4d7455a9575f3dafc9db408d Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 14 Nov 2023 19:34:38 +0300 Subject: [PATCH 21/55] Support quote in ReplyParameters. --- telegram-bot-api/Client.cpp | 78 +++++++++++++++++++++---------------- telegram-bot-api/Client.h | 5 ++- 2 files changed, 47 insertions(+), 36 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index d23930f..daa6678 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -5186,35 +5186,39 @@ void Client::check_message(td::Slice chat_id_str, int64 message_id, bool allow_e template void Client::check_reply_parameters(td::Slice chat_id_str, InputReplyParameters &&reply_parameters, int64 message_thread_id, PromisedQueryPtr query, OnSuccess on_success) { - check_message(chat_id_str, reply_parameters.reply_to_message_id, - reply_parameters.reply_to_message_id <= 0 || reply_parameters.allow_sending_without_reply, - AccessRights::Write, "message to reply", std::move(query), - [this, message_thread_id, on_success = std::move(on_success)](int64 chat_id, int64 reply_to_message_id, - PromisedQueryPtr query) mutable { - CheckedReplyParameters reply_parameters; - reply_parameters.reply_to_message_id = reply_to_message_id; + check_message( + chat_id_str, reply_parameters.reply_to_message_id, + reply_parameters.reply_to_message_id <= 0 || reply_parameters.allow_sending_without_reply, AccessRights::Write, + "message to reply", std::move(query), + [this, message_thread_id, quote = std::move(reply_parameters.quote), on_success = std::move(on_success)]( + int64 chat_id, int64 reply_to_message_id, PromisedQueryPtr query) mutable { + CheckedReplyParameters reply_parameters; + reply_parameters.reply_to_message_id = reply_to_message_id; + if (reply_to_message_id > 0) { + reply_parameters.quote = std::move(quote); + } - if (message_thread_id <= 0) { - return on_success(chat_id, 0, std::move(reply_parameters), std::move(query)); - } + if (message_thread_id <= 0) { + return on_success(chat_id, 0, std::move(reply_parameters), std::move(query)); + } - if (reply_to_message_id != 0) { - const MessageInfo *message_info = get_message(chat_id, reply_to_message_id, true); - 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, std::move(reply_parameters), std::move(query)); - } + if (reply_to_message_id != 0) { + const MessageInfo *message_info = get_message(chat_id, reply_to_message_id, true); + 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, std::move(reply_parameters), std::move(query)); + } - send_request(make_object(chat_id, message_thread_id), - td::make_unique>( - this, chat_id, message_thread_id, std::move(reply_parameters), std::move(query), - std::move(on_success))); - }); + send_request(make_object(chat_id, message_thread_id), + td::make_unique>( + this, chat_id, message_thread_id, std::move(reply_parameters), std::move(query), + std::move(on_success))); + }); } template @@ -5980,9 +5984,10 @@ bool Client::to_bool(td::MutableSlice value) { } td_api::object_ptr Client::get_input_message_reply_to( - const CheckedReplyParameters &reply_parameters) { + CheckedReplyParameters &&reply_parameters) { if (reply_parameters.reply_to_message_id > 0) { - return make_object(0, reply_parameters.reply_to_message_id, nullptr); + return make_object(0, reply_parameters.reply_to_message_id, + std::move(reply_parameters.quote)); } return nullptr; } @@ -6017,10 +6022,15 @@ td::Result Client::get_reply_parameters(td::JsonVa auto &object = value.get_object(); TRY_RESULT(message_id, object.get_required_int_field("message_id")); TRY_RESULT(allow_sending_without_reply, object.get_optional_bool_field("allow_sending_without_reply")); + TRY_RESULT(input_quote, object.get_optional_string_field("quote")); + TRY_RESULT(parse_mode, object.get_optional_string_field("quote_parse_mode")); + TRY_RESULT(quote, + get_formatted_text(std::move(input_quote), std::move(parse_mode), object.extract_field("quote_entities"))); InputReplyParameters result; result.reply_to_message_id = as_tdlib_message_id(td::max(message_id, 0)); result.allow_sending_without_reply = allow_sending_without_reply; + result.quote = std::move(quote); return std::move(result); } @@ -8903,7 +8913,7 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { send_request( make_object( - chat_id, message_thread_id, get_input_message_reply_to(reply_parameters), + chat_id, message_thread_id, get_input_message_reply_to(std::move(reply_parameters)), get_message_send_options(disable_notification, protect_content), std::move(input_message_contents)), td::make_unique(this, chat_id, message_count, std::move(query))); }; @@ -10650,11 +10660,11 @@ void Client::do_send_message(object_ptr input_messa } count++; - send_request( - make_object(chat_id, message_thread_id, get_input_message_reply_to(reply_parameters), - get_message_send_options(disable_notification, protect_content), - std::move(reply_markup), std::move(input_message_content)), - td::make_unique(this, chat_id, std::move(query))); + send_request(make_object(chat_id, message_thread_id, + get_input_message_reply_to(std::move(reply_parameters)), + get_message_send_options(disable_notification, protect_content), + std::move(reply_markup), std::move(input_message_content)), + td::make_unique(this, chat_id, std::move(query))); }; check_reply_parameters(chat_id, std::move(reply_parameters), message_thread_id, std::move(query), std::move(on_success)); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 658ff11..2eb6575 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -248,10 +248,12 @@ class Client final : public WebhookActor::Callback { struct InputReplyParameters { int64 reply_to_message_id = 0; bool allow_sending_without_reply = false; + object_ptr quote; }; struct CheckedReplyParameters { int64 reply_to_message_id = 0; + object_ptr quote; }; struct UserInfo; @@ -350,8 +352,7 @@ class Client final : public WebhookActor::Callback { static bool to_bool(td::MutableSlice value); - static object_ptr get_input_message_reply_to( - const CheckedReplyParameters &reply_parameters); + static object_ptr get_input_message_reply_to(CheckedReplyParameters &&reply_parameters); static td::Result get_reply_parameters(const Query *query); From e66ffb15565a701afc610a5320bd384dc0bf81f4 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 15 Nov 2023 16:18:00 +0300 Subject: [PATCH 22/55] Support chat in ReplyParameters. --- telegram-bot-api/Client.cpp | 98 ++++++++++++++++++++++++------------- telegram-bot-api/Client.h | 2 + 2 files changed, 67 insertions(+), 33 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index daa6678..2967f3f 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -5020,7 +5020,6 @@ void Client::check_chat_access(int64 chat_id, AccessRights access_rights, const case ChatInfo::Type::Supergroup: { auto supergroup_info = get_supergroup_info(chat_info->supergroup_id); CHECK(supergroup_info != nullptr); - bool is_public = !supergroup_info->active_usernames.empty() || supergroup_info->has_location; if (supergroup_info->status->get_id() == td_api::chatMemberStatusBanned::ID) { if (supergroup_info->is_supergroup) { return fail_query(403, "Forbidden: bot was kicked from the supergroup chat", std::move(query)); @@ -5028,8 +5027,9 @@ void Client::check_chat_access(int64 chat_id, AccessRights access_rights, const return fail_query(403, "Forbidden: bot was kicked from the channel chat", std::move(query)); } } + bool is_public = !supergroup_info->active_usernames.empty() || supergroup_info->has_location; bool need_more_access_rights = is_public ? need_edit_access : need_read_access; - if (supergroup_info->status->get_id() == td_api::chatMemberStatusLeft::ID && need_more_access_rights) { + if (!is_chat_member(supergroup_info->status) && need_more_access_rights) { if (supergroup_info->is_supergroup) { return fail_query(403, "Forbidden: bot is not a member of the supergroup chat", std::move(query)); } else { @@ -5186,38 +5186,68 @@ void Client::check_message(td::Slice chat_id_str, int64 message_id, bool allow_e template void Client::check_reply_parameters(td::Slice chat_id_str, InputReplyParameters &&reply_parameters, int64 message_thread_id, PromisedQueryPtr query, OnSuccess on_success) { - check_message( - chat_id_str, reply_parameters.reply_to_message_id, - reply_parameters.reply_to_message_id <= 0 || reply_parameters.allow_sending_without_reply, AccessRights::Write, - "message to reply", std::move(query), - [this, message_thread_id, quote = std::move(reply_parameters.quote), on_success = std::move(on_success)]( - int64 chat_id, int64 reply_to_message_id, PromisedQueryPtr query) mutable { - CheckedReplyParameters reply_parameters; - reply_parameters.reply_to_message_id = reply_to_message_id; - if (reply_to_message_id > 0) { - reply_parameters.quote = std::move(quote); - } - - if (message_thread_id <= 0) { - return on_success(chat_id, 0, std::move(reply_parameters), std::move(query)); - } - - if (reply_to_message_id != 0) { - const MessageInfo *message_info = get_message(chat_id, reply_to_message_id, true); - 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 (chat_id_str == reply_parameters.reply_in_chat_id) { + reply_parameters.reply_in_chat_id.clear(); + } + check_chat( + chat_id_str, AccessRights::Write, std::move(query), + [this, reply_parameters = std::move(reply_parameters), message_thread_id, on_success = std::move(on_success)]( + int64 chat_id, PromisedQueryPtr query) mutable { + auto on_reply_message_resolved = [this, chat_id, message_thread_id, quote = std::move(reply_parameters.quote), + on_success = std::move(on_success)](int64 reply_in_chat_id, + int64 reply_to_message_id, + PromisedQueryPtr query) mutable { + CheckedReplyParameters reply_parameters; + reply_parameters.reply_to_message_id = reply_to_message_id; + if (reply_to_message_id > 0) { + reply_parameters.reply_in_chat_id = reply_in_chat_id; + reply_parameters.quote = std::move(quote); } - } - if (reply_to_message_id == message_thread_id) { - return on_success(chat_id, message_thread_id, std::move(reply_parameters), std::move(query)); + + if (message_thread_id <= 0) { + // if message thread isn't specified, then the message to reply can be only from a different chat + if (reply_parameters.reply_in_chat_id == chat_id) { + reply_parameters.reply_in_chat_id = 0; + } + return on_success(chat_id, 0, std::move(reply_parameters), std::move(query)); + } + + // reply_in_chat_id must be non-zero only for replies in different chats or different topics + if (reply_to_message_id > 0 && reply_parameters.reply_in_chat_id == chat_id) { + const MessageInfo *message_info = get_message(reply_in_chat_id, reply_to_message_id, true); + CHECK(message_info != nullptr); + if (message_info->message_thread_id == message_thread_id) { + reply_parameters.reply_in_chat_id = 0; + } + } + + send_request(make_object(chat_id, message_thread_id), + td::make_unique>( + this, chat_id, message_thread_id, std::move(reply_parameters), std::move(query), + std::move(on_success))); + }; + if (reply_parameters.reply_to_message_id <= 0) { + return on_reply_message_resolved(0, 0, std::move(query)); } - send_request(make_object(chat_id, message_thread_id), - td::make_unique>( - this, chat_id, message_thread_id, std::move(reply_parameters), std::move(query), - std::move(on_success))); + auto on_reply_chat_resolved = [this, reply_to_message_id = reply_parameters.reply_to_message_id, + allow_sending_without_reply = reply_parameters.allow_sending_without_reply, + on_success = std::move(on_reply_message_resolved)]( + int64 reply_in_chat_id, PromisedQueryPtr query) mutable { + if (!have_message_access(reply_in_chat_id)) { + return fail_query_with_error(std::move(query), 400, "MESSAGE_NOT_FOUND", "message to reply not found"); + } + + send_request(make_object(reply_in_chat_id, reply_to_message_id), + td::make_unique>( + this, reply_in_chat_id, reply_to_message_id, allow_sending_without_reply, "message to reply", + std::move(query), std::move(on_success))); + }; + if (reply_parameters.reply_in_chat_id.empty()) { + return on_reply_chat_resolved(chat_id, std::move(query)); + } + check_chat(reply_parameters.reply_in_chat_id, AccessRights::Read, std::move(query), + std::move(on_reply_chat_resolved)); }); } @@ -5986,8 +6016,8 @@ bool Client::to_bool(td::MutableSlice value) { td_api::object_ptr Client::get_input_message_reply_to( CheckedReplyParameters &&reply_parameters) { if (reply_parameters.reply_to_message_id > 0) { - return make_object(0, reply_parameters.reply_to_message_id, - std::move(reply_parameters.quote)); + return make_object( + reply_parameters.reply_in_chat_id, reply_parameters.reply_to_message_id, std::move(reply_parameters.quote)); } return nullptr; } @@ -6020,6 +6050,7 @@ td::Result Client::get_reply_parameters(td::JsonVa return td::Status::Error(400, "Object expected as reply parameters"); } auto &object = value.get_object(); + TRY_RESULT(chat_id, object.get_optional_string_field("chat_id")); TRY_RESULT(message_id, object.get_required_int_field("message_id")); TRY_RESULT(allow_sending_without_reply, object.get_optional_bool_field("allow_sending_without_reply")); TRY_RESULT(input_quote, object.get_optional_string_field("quote")); @@ -6028,6 +6059,7 @@ td::Result Client::get_reply_parameters(td::JsonVa get_formatted_text(std::move(input_quote), std::move(parse_mode), object.extract_field("quote_entities"))); InputReplyParameters result; + result.reply_in_chat_id = std::move(chat_id); result.reply_to_message_id = as_tdlib_message_id(td::max(message_id, 0)); result.allow_sending_without_reply = allow_sending_without_reply; result.quote = std::move(quote); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 2eb6575..fc1bc26 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -246,12 +246,14 @@ class Client final : public WebhookActor::Callback { }; struct InputReplyParameters { + td::string reply_in_chat_id; int64 reply_to_message_id = 0; bool allow_sending_without_reply = false; object_ptr quote; }; struct CheckedReplyParameters { + int64 reply_in_chat_id = 0; int64 reply_to_message_id = 0; object_ptr quote; }; From 59436578ee900968026f189f50e35ad181c7ec5b Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 4 Dec 2023 13:42:00 +0300 Subject: [PATCH 23/55] Update TDLib to 1.8.22. --- td | 2 +- telegram-bot-api/Client.cpp | 19 +++++++++++++------ telegram-bot-api/Client.h | 4 ++-- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/td b/td index 9184b3e..4dbcfce 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 9184b3e62de59663a59d3500528aee7e5f0d83fa +Subproject commit 4dbcfce77d6f2ef95b3f1d2ef8ef6b0c66a4fd4d diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 2967f3f..282653c 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2272,9 +2272,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("external_reply", JsonExternalReplyInfo(message_->reply_to_message.get(), client_)); } if (message_->reply_to_message != nullptr && message_->reply_to_message->quote_ != nullptr) { - object("quote", message_->reply_to_message->quote_->text_); - if (!message_->reply_to_message->quote_->entities_.empty()) { - object("quote_entities", JsonVectorEntities(message_->reply_to_message->quote_->entities_, client_)); + object("quote", message_->reply_to_message->quote_->text_->text_); + if (!message_->reply_to_message->quote_->text_->entities_.empty()) { + object("quote_entities", JsonVectorEntities(message_->reply_to_message->quote_->text_->entities_, client_)); } } if (message_->media_album_id != 0) { @@ -2605,6 +2605,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("chat_shared", JsonChatShared(content)); break; } + case td_api::messageStory::ID: + object("story", JsonEmptyObject()); + break; case td_api::messageChatSetBackground::ID: break; case td_api::messagePremiumGiftCode::ID: @@ -2617,8 +2620,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("giveaway", JsonGiveaway(content, client_)); break; } - case td_api::messageStory::ID: - object("story", JsonEmptyObject()); + case td_api::messagePremiumGiveawayCompleted::ID: break; default: UNREACHABLE(); @@ -6062,7 +6064,7 @@ td::Result Client::get_reply_parameters(td::JsonVa result.reply_in_chat_id = std::move(chat_id); result.reply_to_message_id = as_tdlib_message_id(td::max(message_id, 0)); result.allow_sending_without_reply = allow_sending_without_reply; - result.quote = std::move(quote); + result.quote = td_api::make_object(std::move(quote), 0); return std::move(result); } @@ -11737,6 +11739,8 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr(message->content_.get()) ->old_background_message_id_; + case td_api::messagePremiumGiveawayCompleted::ID: + return static_cast(message->content_.get()) + ->giveaway_message_id_; case td_api::messagePaymentSuccessful::ID: UNREACHABLE(); return static_cast(0); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index fc1bc26..07ad798 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -249,13 +249,13 @@ class Client final : public WebhookActor::Callback { td::string reply_in_chat_id; int64 reply_to_message_id = 0; bool allow_sending_without_reply = false; - object_ptr quote; + object_ptr quote; }; struct CheckedReplyParameters { int64 reply_in_chat_id = 0; int64 reply_to_message_id = 0; - object_ptr quote; + object_ptr quote; }; struct UserInfo; From 2c5ff070b3b6bd811a92d38e4a692b2364ff2a09 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 4 Dec 2023 14:18:57 +0300 Subject: [PATCH 24/55] Add class TextQuote. --- telegram-bot-api/Client.cpp | 26 ++++++++++++++++++++++---- telegram-bot-api/Client.h | 1 + 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 282653c..d41e4b3 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2192,6 +2192,27 @@ class Client::JsonExternalReplyInfo final : public td::Jsonable { } }; +class Client::JsonTextQuote final : public td::Jsonable { + public: + JsonTextQuote(const td_api::textQuote *quote, const Client *client) : quote_(quote), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("text", quote_->text_->text_); + if (!quote_->text_->entities_.empty()) { + object("entities", JsonVectorEntities(quote_->text_->entities_, client_)); + } + object("position", quote_->position_); + if (quote_->is_manual_) { + object("is_manual", td::JsonTrue()); + } + } + + private: + const td_api::textQuote *quote_; + const Client *client_; +}; + void Client::JsonMessage::store(td::JsonValueScope *scope) const { CHECK(message_ != nullptr); auto object = scope->enter_object(); @@ -2272,10 +2293,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("external_reply", JsonExternalReplyInfo(message_->reply_to_message.get(), client_)); } if (message_->reply_to_message != nullptr && message_->reply_to_message->quote_ != nullptr) { - object("quote", message_->reply_to_message->quote_->text_->text_); - if (!message_->reply_to_message->quote_->text_->entities_.empty()) { - object("quote_entities", JsonVectorEntities(message_->reply_to_message->quote_->text_->entities_, client_)); - } + object("quote", JsonTextQuote(message_->reply_to_message->quote_.get(), client_)); } if (message_->media_album_id != 0) { object("media_group_id", td::to_string(message_->media_album_id)); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 07ad798..bd1c65c 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -99,6 +99,7 @@ class Client final : public WebhookActor::Callback { class JsonMessageSender; class JsonMessageOrigin; class JsonExternalReplyInfo; + class JsonTextQuote; class JsonLinkPreviewOptions; class JsonAnimation; class JsonAudio; From 9620d43700c32fe3b9bbdb49a1486351e343bb6d Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 4 Dec 2023 14:31:45 +0300 Subject: [PATCH 25/55] Support quote position in reply parameters. --- telegram-bot-api/Client.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index d41e4b3..624d208 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -6077,12 +6077,13 @@ td::Result Client::get_reply_parameters(td::JsonVa TRY_RESULT(parse_mode, object.get_optional_string_field("quote_parse_mode")); TRY_RESULT(quote, get_formatted_text(std::move(input_quote), std::move(parse_mode), object.extract_field("quote_entities"))); + TRY_RESULT(quote_position, object.get_optional_int_field("quote_position")); InputReplyParameters result; result.reply_in_chat_id = std::move(chat_id); result.reply_to_message_id = as_tdlib_message_id(td::max(message_id, 0)); result.allow_sending_without_reply = allow_sending_without_reply; - result.quote = td_api::make_object(std::move(quote), 0); + result.quote = td_api::make_object(std::move(quote), quote_position); return std::move(result); } From 6fdb4d241614efbf1ab8232d9bd751b998f4a240 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 4 Dec 2023 15:23:59 +0300 Subject: [PATCH 26/55] Add Message.giveaway_completed. --- telegram-bot-api/Client.cpp | 69 ++++++++++++++++++++++++++----------- telegram-bot-api/Client.h | 1 + 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 624d208..466383f 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -896,6 +896,24 @@ class Client::JsonChat final : public td::Jsonable { int64 pinned_message_id_; }; +class Client::JsonDeletedMessage final : public td::Jsonable { + public: + JsonDeletedMessage(int64 chat_id, int64 message_id, const Client *client) + : chat_id_(chat_id), message_id_(message_id), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("message_id", as_client_message_id(message_id_)); + object("chat", JsonChat(chat_id_, client_)); + object("date", 0); + } + + private: + int64 chat_id_; + int64 message_id_; + const Client *client_; +}; + class Client::JsonMessageSender final : public td::Jsonable { public: JsonMessageSender(const td_api::MessageSender *sender_id, const Client *client) @@ -1937,6 +1955,31 @@ class Client::JsonGiveaway final : public td::Jsonable { const Client *client_; }; +class Client::JsonGiveawayCompleted final : public td::Jsonable { + public: + JsonGiveawayCompleted(const td_api::messagePremiumGiveawayCompleted *giveaway_completed, int64 chat_id, + const Client *client) + : giveaway_completed_(giveaway_completed), chat_id_(chat_id), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("winner_count", giveaway_completed_->winner_count_); + if (giveaway_completed_->unclaimed_prize_count_ > 0) { + object("unclaimed_prize_count", giveaway_completed_->unclaimed_prize_count_); + } + const MessageInfo *giveaway_message = + client_->get_message(chat_id_, giveaway_completed_->giveaway_message_id_, true); + if (giveaway_message != nullptr) { + object("giveaway_message", JsonMessage(giveaway_message, true, "giveaway completed", client_)); + } + } + + private: + const td_api::messagePremiumGiveawayCompleted *giveaway_completed_; + int64 chat_id_; + const Client *client_; +}; + class Client::JsonWebAppInfo final : public td::Jsonable { public: explicit JsonWebAppInfo(const td::string &url) : url_(url) { @@ -2638,8 +2681,11 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("giveaway", JsonGiveaway(content, client_)); break; } - case td_api::messagePremiumGiveawayCompleted::ID: + case td_api::messagePremiumGiveawayCompleted::ID: { + auto content = static_cast(message_->content.get()); + object("giveaway_completed", JsonGiveawayCompleted(content, message_->chat_id, client_)); break; + } default: UNREACHABLE(); } @@ -2657,24 +2703,6 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { } } -class Client::JsonDeletedMessage final : public td::Jsonable { - public: - JsonDeletedMessage(int64 chat_id, int64 message_id, const Client *client) - : chat_id_(chat_id), message_id_(message_id), client_(client) { - } - void store(td::JsonValueScope *scope) const { - auto object = scope->enter_object(); - object("message_id", as_client_message_id(message_id_)); - object("chat", JsonChat(chat_id_, client_)); - object("date", 0); - } - - private: - int64 chat_id_; - int64 message_id_; - const Client *client_; -}; - class Client::JsonMessageId final : public td::Jsonable { public: explicit JsonMessageId(int64 message_id) : message_id_(message_id) { @@ -11648,6 +11676,7 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr Date: Mon, 4 Dec 2023 15:32:17 +0300 Subject: [PATCH 27/55] Store identifier of inaccessible pinned message. --- telegram-bot-api/Client.cpp | 12 ++++-------- telegram-bot-api/Client.h | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 466383f..c142f6d 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -896,9 +896,9 @@ class Client::JsonChat final : public td::Jsonable { int64 pinned_message_id_; }; -class Client::JsonDeletedMessage final : public td::Jsonable { +class Client::JsonInaccessibleMessage final : public td::Jsonable { public: - JsonDeletedMessage(int64 chat_id, int64 message_id, const Client *client) + JsonInaccessibleMessage(int64 chat_id, int64 message_id, const Client *client) : chat_id_(chat_id), message_id_(message_id), client_(client) { } void store(td::JsonValueScope *scope) const { @@ -2557,6 +2557,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("pinned_message", JsonMessage(pinned_message, false, "pin in " + source_, client_)); } else if (need_reply_) { LOG(INFO) << "Pinned unknown, inaccessible or deleted message " << message_id; + object("pinned_message", JsonInaccessibleMessage(message_->chat_id, message_id, client_)); } } break; @@ -2838,7 +2839,7 @@ class Client::JsonCallbackQuery final : public td::Jsonable { if (message_info_ != nullptr) { object("message", JsonMessage(message_info_, true, "callback query", client_)); } else { - object("message", JsonDeletedMessage(chat_id_, message_id_, client_)); + object("message", JsonInaccessibleMessage(chat_id_, message_id_, client_)); } object("chat_instance", td::to_string(chat_instance_)); client_->json_store_callback_query_payload(object, payload_); @@ -11745,11 +11746,6 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr Date: Mon, 11 Dec 2023 20:55:10 +0300 Subject: [PATCH 28/55] Add deleteMessages method. --- telegram-bot-api/Client.cpp | 124 ++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 10 +++ 2 files changed, 134 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index c142f6d..9d97a9e 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -241,6 +241,7 @@ bool Client::init_methods() { methods_.emplace("editmessagecaption", &Client::process_edit_message_caption_query); methods_.emplace("editmessagereplymarkup", &Client::process_edit_message_reply_markup_query); methods_.emplace("deletemessage", &Client::process_delete_message_query); + methods_.emplace("deletemessages", &Client::process_delete_messages_query); methods_.emplace("createinvoicelink", &Client::process_create_invoice_link_query); methods_.emplace("setgamescore", &Client::process_set_game_score_query); methods_.emplace("getgamehighscores", &Client::process_get_game_high_scores_query); @@ -3897,6 +3898,57 @@ class Client::TdOnCheckMessageCallback final : public TdQueryCallback { OnSuccess on_success_; }; +template +class Client::TdOnCheckMessagesCallback final : public TdQueryCallback { + public: + TdOnCheckMessagesCallback(Client *client, int64 chat_id, bool allow_empty, td::Slice message_type, + PromisedQueryPtr query, OnSuccess on_success) + : client_(client) + , chat_id_(chat_id) + , allow_empty_(allow_empty) + , message_type_(message_type) + , 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 messages in " << chat_id_ << ": " << message_type_; + } + if (allow_empty_) { + return on_success_(chat_id_, td::vector(), std::move(query_)); + } + return fail_query_with_error(std::move(query_), std::move(error), PSLICE() << message_type_ << " not found"); + } + + CHECK(result->get_id() == td_api::messages::ID); + auto messages = move_object_as(result); + td::vector message_ids; + for (auto &message : messages->messages_) { + if (message == nullptr) { + if (!allow_empty_) { + return fail_query_with_error(std::move(query_), 400, PSLICE() << message_type_ << " not found"); + } + continue; + } + auto full_message_id = client_->add_message(std::move(message)); + CHECK(full_message_id.chat_id == chat_id_); + message_ids.push_back(full_message_id.message_id); + } + on_success_(chat_id_, std::move(message_ids), std::move(query_)); + } + + private: + Client *client_; + int64 chat_id_; + bool allow_empty_; + td::Slice message_type_; + PromisedQueryPtr query_; + OnSuccess on_success_; +}; + template class Client::TdOnCheckMessageThreadCallback final : public TdQueryCallback { public: @@ -5232,6 +5284,24 @@ void Client::check_message(td::Slice chat_id_str, int64 message_id, bool allow_e }); } +template +void Client::check_messages(td::Slice chat_id_str, td::vector message_ids, bool allow_empty, + AccessRights access_rights, td::Slice message_type, PromisedQueryPtr query, + OnSuccess on_success) { + check_chat(chat_id_str, access_rights, std::move(query), + [this, message_ids = std::move(message_ids), allow_empty, message_type, + on_success = std::move(on_success)](int64 chat_id, PromisedQueryPtr query) mutable { + if (!have_message_access(chat_id)) { + return fail_query_with_error(std::move(query), 400, "MESSAGE_NOT_FOUND", + PSLICE() << message_type << " not found"); + } + + send_request(make_object(chat_id, std::move(message_ids)), + td::make_unique>( + this, chat_id, allow_empty, message_type, std::move(query), std::move(on_success))); + }); +} + template void Client::check_reply_parameters(td::Slice chat_id_str, InputReplyParameters &&reply_parameters, int64 message_thread_id, PromisedQueryPtr query, OnSuccess on_success) { @@ -8350,6 +8420,46 @@ td::int64 Client::get_message_id(const Query *query, td::Slice field_name) { return as_tdlib_message_id(arg); } +td::Result> Client::get_message_ids(const Query *query, size_t max_count, td::Slice field_name) { + auto message_ids_str = query->arg(field_name); + if (message_ids_str.empty()) { + return td::Status::Error(400, "Message identifiers are not specified"); + } + + auto r_value = json_decode(message_ids_str); + if (r_value.is_error()) { + return td::Status::Error(400, PSLICE() << "Can't parse " << field_name << " JSON object"); + } + auto value = r_value.move_as_ok(); + if (value.type() != td::JsonValue::Type::Array) { + return td::Status::Error(400, "Expected an Array of message identifiers"); + } + if (value.get_array().size() > max_count) { + return td::Status::Error(400, "Too many message identifiers specified"); + } + + td::vector message_ids; + for (auto &message_id : value.get_array()) { + td::Slice number; + if (message_id.type() == td::JsonValue::Type::Number) { + number = message_id.get_number(); + } else if (message_id.type() == td::JsonValue::Type::String) { + number = message_id.get_string(); + } else { + return td::Status::Error(400, "Message identifier must be a Number"); + } + auto parsed_message_id = td::to_integer_safe(number); + if (parsed_message_id.is_error()) { + return td::Status::Error(400, "Can't parse message identifier as Number"); + } + if (parsed_message_id.ok() <= 0) { + return td::Status::Error(400, "Invalid message identifier specified"); + } + message_ids.push_back(as_tdlib_message_id(parsed_message_id.ok())); + } + return std::move(message_ids); +} + td::Result Client::get_inline_message_id(const Query *query, td::Slice field_name) { auto s_arg = query->arg(field_name); if (s_arg.empty()) { @@ -9214,6 +9324,20 @@ td::Status Client::process_delete_message_query(PromisedQueryPtr &query) { return td::Status::OK(); } +td::Status Client::process_delete_messages_query(PromisedQueryPtr &query) { + auto chat_id = query->arg("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"); + } + check_messages(chat_id, std::move(message_ids), true, AccessRights::Write, "message to delete", std::move(query), + [this](int64 chat_id, td::vector message_ids, PromisedQueryPtr query) { + send_request(make_object(chat_id, std::move(message_ids), true), + td::make_unique(std::move(query))); + }); + return td::Status::OK(); +} + td::Status Client::process_create_invoice_link_query(PromisedQueryPtr &query) { TRY_RESULT(input_message_invoice, get_input_message_invoice(query.get())); send_request(make_object(std::move(input_message_invoice)), diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index cb922b2..a64cddd 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -278,6 +278,8 @@ class Client final : public WebhookActor::Callback { template class TdOnCheckMessageCallback; template + class TdOnCheckMessagesCallback; + template class TdOnCheckMessageThreadCallback; template class TdOnCheckRemoteFileIdCallback; @@ -318,6 +320,10 @@ class Client final : public WebhookActor::Callback { void check_message(td::Slice chat_id_str, int64 message_id, bool allow_empty, AccessRights access_rights, td::Slice message_type, PromisedQueryPtr query, OnSuccess on_success); + template + void check_messages(td::Slice chat_id_str, td::vector message_ids, bool allow_empty, + AccessRights access_rights, td::Slice message_type, PromisedQueryPtr query, OnSuccess on_success); + template void check_reply_parameters(td::Slice chat_id_str, InputReplyParameters &&reply_parameters, int64 message_thread_id, PromisedQueryPtr query, OnSuccess on_success); @@ -529,6 +535,9 @@ class Client final : public WebhookActor::Callback { static int64 get_message_id(const Query *query, td::Slice field_name = td::Slice("message_id")); + static td::Result> get_message_ids(const Query *query, size_t max_count, + td::Slice field_name = td::Slice("message_ids")); + static td::Result get_inline_message_id(const Query *query, td::Slice field_name = td::Slice("inline_message_id")); @@ -591,6 +600,7 @@ class Client final : public WebhookActor::Callback { td::Status process_edit_message_caption_query(PromisedQueryPtr &query); td::Status process_edit_message_reply_markup_query(PromisedQueryPtr &query); td::Status process_delete_message_query(PromisedQueryPtr &query); + td::Status process_delete_messages_query(PromisedQueryPtr &query); td::Status process_create_invoice_link_query(PromisedQueryPtr &query); td::Status process_set_game_score_query(PromisedQueryPtr &query); td::Status process_get_game_high_scores_query(PromisedQueryPtr &query); From b039c8e92710dfb0e754a6794fd3a2f6cecc960c Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 12 Dec 2023 14:37:51 +0300 Subject: [PATCH 29/55] Add forwardMessages method. --- telegram-bot-api/Client.cpp | 87 ++++++++++++++++++++++++++++++++++++- telegram-bot-api/Client.h | 4 +- 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 9d97a9e..57b1bb5 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -232,6 +232,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); @@ -3575,6 +3576,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) @@ -8513,7 +8552,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) { @@ -9076,6 +9119,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 a64cddd..4bf58da 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; @@ -188,6 +188,7 @@ class Client final : public WebhookActor::Callback { class TdOnGetUserProfilePhotosCallback; class TdOnSendMessageCallback; class TdOnSendMessageAlbumCallback; + class TdOnForwardMessagesCallback; class TdOnDeleteFailedToSendMessageCallback; class TdOnEditMessageCallback; class TdOnEditInlineMessageCallback; @@ -592,6 +593,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); From 57cad9c0a81f814a57a1cdd32bf3169c6e141766 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 12 Dec 2023 14:48:35 +0300 Subject: [PATCH 30/55] Add copyMessages method. --- telegram-bot-api/Client.cpp | 47 ++++++++++++++++++++++++++++++++++++- telegram-bot-api/Client.h | 1 + 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 57b1bb5..4a14c8d 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -231,6 +231,7 @@ bool Client::init_methods() { methods_.emplace("sendpoll", &Client::process_send_poll_query); methods_.emplace("stoppoll", &Client::process_stop_poll_query); methods_.emplace("copymessage", &Client::process_copy_message_query); + methods_.emplace("copymessages", &Client::process_copy_messages_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); @@ -8552,7 +8553,7 @@ 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) { - if (query.query->method() == "forwardmessages") { + if (query.query->method() == "forwardmessages" || query.query->method() == "copymessages") { 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))); @@ -9107,6 +9108,50 @@ td::Status Client::process_copy_message_query(PromisedQueryPtr &query) { return td::Status::OK(); } +td::Status Client::process_copy_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 remove_caption = to_bool(query->arg("remove_caption")); + + auto on_success = [this, from_chat_id = from_chat_id.str(), message_ids = std::move(message_ids), + disable_notification, protect_content, + remove_caption](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, remove_caption]( + 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), true, remove_caption), + 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_forward_message_query(PromisedQueryPtr &query) { TRY_RESULT(from_chat_id, get_required_string_arg(query.get(), "from_chat_id")); auto message_id = get_message_id(query.get()); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 4bf58da..53b9b55 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -592,6 +592,7 @@ class Client final : public WebhookActor::Callback { td::Status process_send_poll_query(PromisedQueryPtr &query); td::Status process_stop_poll_query(PromisedQueryPtr &query); td::Status process_copy_message_query(PromisedQueryPtr &query); + td::Status process_copy_messages_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); From f5f7bbb57f1e9bfdd1aa006a1f0c600947831e8f Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 20 Dec 2023 15:14:10 +0300 Subject: [PATCH 31/55] Add Chat.available_reactions. --- telegram-bot-api/Client.cpp | 46 +++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 2 ++ 2 files changed, 48 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 4a14c8d..8abc997 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -586,6 +586,32 @@ class Client::JsonLocation final : public td::Jsonable { int32 proximity_alert_radius_; }; +class Client::JsonReactionType final : public td::Jsonable { + public: + explicit JsonReactionType(const td_api::ReactionType *reaction_type) : reaction_type_(reaction_type) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + CHECK(reaction_type_ != nullptr); + switch (reaction_type_->get_id()) { + case td_api::reactionTypeEmoji::ID: + object("type", "emoji"); + object("emoji", static_cast(reaction_type_)->emoji_); + break; + case td_api::reactionTypeCustomEmoji::ID: + object("type", "custom_emoji"); + object("custom_emoji_id", + td::to_string(static_cast(reaction_type_)->custom_emoji_id_)); + break; + default: + UNREACHABLE(); + } + } + + private: + const td_api::ReactionType *reaction_type_; +}; + class Client::JsonChatPermissions final : public td::Jsonable { public: explicit JsonChatPermissions(const td_api::chatPermissions *chat_permissions) : chat_permissions_(chat_permissions) { @@ -881,6 +907,11 @@ class Client::JsonChat final : public td::Jsonable { if (chat_info->message_auto_delete_time != 0) { object("message_auto_delete_time", chat_info->message_auto_delete_time); } + if (chat_info->available_reactions != nullptr) { + object("available_reactions", + td::json_array(chat_info->available_reactions->reactions_, + [](const auto &reaction) { return JsonReactionType(reaction.get()); })); + } CHECK(chat_info->accent_color_id != -1); object("accent_color_id", chat_info->accent_color_id); if (chat_info->background_custom_emoji_id != 0) { @@ -5819,6 +5850,9 @@ void Client::on_update(object_ptr result) { chat_info->photo_info = std::move(chat->photo_); chat_info->permissions = std::move(chat->permissions_); chat_info->message_auto_delete_time = chat->message_auto_delete_time_; + if (chat->available_reactions_->get_id() == td_api::chatAvailableReactionsSome::ID) { + chat_info->available_reactions = move_object_as(chat->available_reactions_); + } chat_info->accent_color_id = chat->accent_color_id_; chat_info->background_custom_emoji_id = chat->background_custom_emoji_id_; chat_info->has_protected_content = chat->has_protected_content_; @@ -5852,6 +5886,18 @@ void Client::on_update(object_ptr result) { chat_info->message_auto_delete_time = update->message_auto_delete_time_; break; } + case td_api::updateChatAvailableReactions::ID: { + auto update = move_object_as(result); + auto chat_info = add_chat(update->chat_id_); + CHECK(chat_info->type != ChatInfo::Type::Unknown); + if (update->available_reactions_->get_id() == td_api::chatAvailableReactionsSome::ID) { + chat_info->available_reactions = + move_object_as(update->available_reactions_); + } else { + chat_info->available_reactions = nullptr; + } + break; + } case td_api::updateChatAccentColor::ID: { auto update = move_object_as(result); auto chat_info = add_chat(update->chat_id_); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 53b9b55..5520f11 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -91,6 +91,7 @@ class Client final : public WebhookActor::Callback { class JsonDatedFiles; class JsonUser; class JsonUsers; + class JsonReactionType; class JsonChatPermissions; class JsonChatPhotoInfo; class JsonChatLocation; @@ -826,6 +827,7 @@ class Client final : public WebhookActor::Callback { int32 accent_color_id = -1; int64 background_custom_emoji_id = 0; bool has_protected_content = false; + object_ptr available_reactions; object_ptr photo_info; object_ptr permissions; union { From fa0bc023fb8257acc80053d169dcd94bb3f8d58c Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 20 Dec 2023 16:05:37 +0300 Subject: [PATCH 32/55] Update TDLib to 1.8.23. --- td | 2 +- telegram-bot-api/Client.cpp | 30 ++++++++++++++---------------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/td b/td index 4dbcfce..27c3eae 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 4dbcfce77d6f2ef95b3f1d2ef8ef6b0c66a4fd4d +Subproject commit 27c3eaeb4964bd5f18d8488e354abde1a4383e49 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 8abc997..4ec77d5 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1931,16 +1931,16 @@ class Client::JsonWriteAccessAllowed final : public td::Jsonable { class Client::JsonUserShared final : public td::Jsonable { public: - explicit JsonUserShared(const td_api::messageUserShared *user_shared) : user_shared_(user_shared) { + explicit JsonUserShared(const td_api::messageUsersShared *users_shared) : users_shared_(users_shared) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("user_id", user_shared_->user_id_); - object("request_id", user_shared_->button_id_); + object("user_id", users_shared_->user_ids_[0]); + object("request_id", users_shared_->button_id_); } private: - const td_api::messageUserShared *user_shared_; + const td_api::messageUsersShared *users_shared_; }; class Client::JsonChatShared final : public td::Jsonable { @@ -2691,8 +2691,8 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { } break; } - case td_api::messageUserShared::ID: { - auto content = static_cast(message_->content.get()); + case td_api::messageUsersShared::ID: { + auto content = static_cast(message_->content.get()); object("user_shared", JsonUserShared(content)); break; } @@ -2716,6 +2716,8 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("giveaway", JsonGiveaway(content, client_)); break; } + case td_api::messagePremiumGiveawayWinners::ID: + break; case td_api::messagePremiumGiveawayCompleted::ID: { auto content = static_cast(message_->content.get()); object("giveaway_completed", JsonGiveawayCompleted(content, message_->chat_id, client_)); @@ -5898,17 +5900,11 @@ void Client::on_update(object_ptr result) { } break; } - case td_api::updateChatAccentColor::ID: { - auto update = move_object_as(result); + case td_api::updateChatAccentColors::ID: { + auto update = move_object_as(result); auto chat_info = add_chat(update->chat_id_); CHECK(chat_info->type != ChatInfo::Type::Unknown); chat_info->accent_color_id = update->accent_color_id_; - break; - } - case td_api::updateChatBackgroundCustomEmoji::ID: { - auto update = move_object_as(result); - auto chat_info = add_chat(update->chat_id_); - CHECK(chat_info->type != ChatInfo::Type::Unknown); chat_info->background_custom_emoji_id = update->background_custom_emoji_id_; break; } @@ -6322,8 +6318,8 @@ td::Result> Client::get_keyboard_butt auto restrict_user_is_premium = request_user_object.has_field("user_is_premium"); TRY_RESULT(user_is_premium, request_user_object.get_optional_bool_field("user_is_premium")); return make_object( - text, make_object(id, restrict_user_is_bot, user_is_bot, - restrict_user_is_premium, user_is_premium)); + text, make_object(id, restrict_user_is_bot, user_is_bot, + restrict_user_is_premium, user_is_premium, 1)); } if (object.has_field("request_chat")) { @@ -12083,6 +12079,8 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr Date: Wed, 20 Dec 2023 16:09:15 +0300 Subject: [PATCH 33/55] Add fields chat.profile_accent_color_id and chat.profile_background_custom_emoji_id. --- telegram-bot-api/Client.cpp | 10 ++++++++++ telegram-bot-api/Client.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 4ec77d5..f3523db 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -917,6 +917,12 @@ class Client::JsonChat final : public td::Jsonable { if (chat_info->background_custom_emoji_id != 0) { object("background_custom_emoji_id", td::to_string(chat_info->background_custom_emoji_id)); } + if (chat_info->profile_accent_color_id != -1) { + object("profile_accent_color_id", chat_info->profile_accent_color_id); + } + if (chat_info->profile_background_custom_emoji_id != 0) { + object("profile_background_custom_emoji_id", td::to_string(chat_info->profile_background_custom_emoji_id)); + } if (chat_info->has_protected_content) { object("has_protected_content", td::JsonTrue()); } @@ -5857,6 +5863,8 @@ void Client::on_update(object_ptr result) { } chat_info->accent_color_id = chat->accent_color_id_; chat_info->background_custom_emoji_id = chat->background_custom_emoji_id_; + chat_info->profile_accent_color_id = chat->profile_accent_color_id_; + chat_info->profile_background_custom_emoji_id = chat->profile_background_custom_emoji_id_; chat_info->has_protected_content = chat->has_protected_content_; break; } @@ -5906,6 +5914,8 @@ void Client::on_update(object_ptr result) { CHECK(chat_info->type != ChatInfo::Type::Unknown); chat_info->accent_color_id = update->accent_color_id_; chat_info->background_custom_emoji_id = update->background_custom_emoji_id_; + chat_info->profile_accent_color_id = update->profile_accent_color_id_; + chat_info->profile_background_custom_emoji_id = update->profile_background_custom_emoji_id_; break; } case td_api::updateChatHasProtectedContent::ID: { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 5520f11..a55fc6f 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -825,7 +825,9 @@ class Client final : public WebhookActor::Callback { td::string title; int32 message_auto_delete_time = 0; int32 accent_color_id = -1; + int32 profile_accent_color_id = -1; int64 background_custom_emoji_id = 0; + int64 profile_background_custom_emoji_id = 0; bool has_protected_content = false; object_ptr available_reactions; object_ptr photo_info; From 1f512433eff98978e134d0cf7ecfa059135292f5 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 20 Dec 2023 16:19:06 +0300 Subject: [PATCH 34/55] Add "has_public_winners" and "prize_description" giveaway fields. --- telegram-bot-api/Client.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index f3523db..bf8fd0c 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1981,10 +1981,16 @@ class Client::JsonGiveaway final : public td::Jsonable { if (giveaway_->parameters_->only_new_members_) { object("only_new_members", td::JsonTrue()); } + if (giveaway_->parameters_->has_public_winners_) { + object("has_public_winners", td::JsonTrue()); + } if (!giveaway_->parameters_->country_codes_.empty()) { object("country_codes", td::json_array(giveaway_->parameters_->country_codes_, [](td::Slice country_code) { return td::JsonString(country_code); })); } + if (!giveaway_->parameters_->prize_description_.empty()) { + object("prize_description", giveaway_->parameters_->prize_description_); + } if (giveaway_->month_count_ > 0) { object("premium_subscription_month_count", giveaway_->month_count_); } From 1320b03bc55f9c7903c7c277c2058cc4ef52f7d1 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 20 Dec 2023 16:44:01 +0300 Subject: [PATCH 35/55] Add Message.giveaway_winners. --- telegram-bot-api/Client.cpp | 50 ++++++++++++++++++++++++++++++++++--- telegram-bot-api/Client.h | 1 + 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index bf8fd0c..ce40f68 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2001,6 +2001,43 @@ class Client::JsonGiveaway final : public td::Jsonable { const Client *client_; }; +class Client::JsonGiveawayWinners final : public td::Jsonable { + public: + JsonGiveawayWinners(const td_api::messagePremiumGiveawayWinners *giveaway_winners, const Client *client) + : giveaway_winners_(giveaway_winners), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("chat", JsonChat(giveaway_winners_->boosted_chat_id_, client_)); + object("giveaway_message_id", as_client_message_id(giveaway_winners_->giveaway_message_id_)); + if (giveaway_winners_->additional_chat_count_ > 0) { + object("additional_chat_count", giveaway_winners_->additional_chat_count_); + } + object("winners_selection_date", giveaway_winners_->actual_winners_selection_date_); + if (giveaway_winners_->only_new_members_) { + object("only_new_members", td::JsonTrue()); + } + if (giveaway_winners_->was_refunded_) { + object("was_refunded", td::JsonTrue()); + } + if (giveaway_winners_->month_count_ > 0) { + object("premium_subscription_month_count", giveaway_winners_->month_count_); + } + if (!giveaway_winners_->prize_description_.empty()) { + object("prize_description", giveaway_winners_->prize_description_); + } + object("winner_count", giveaway_winners_->winner_count_); + if (giveaway_winners_->unclaimed_prize_count_ > 0) { + object("unclaimed_prize_count", giveaway_winners_->unclaimed_prize_count_); + } + object("winners", JsonUsers(giveaway_winners_->winner_user_ids_, client_)); + } + + private: + const td_api::messagePremiumGiveawayWinners *giveaway_winners_; + const Client *client_; +}; + class Client::JsonGiveawayCompleted final : public td::Jsonable { public: JsonGiveawayCompleted(const td_api::messagePremiumGiveawayCompleted *giveaway_completed, int64 chat_id, @@ -2261,6 +2298,11 @@ class Client::JsonExternalReplyInfo final : public td::Jsonable { object("giveaway", JsonGiveaway(content, client_)); break; } + case td_api::messagePremiumGiveawayWinners::ID: { + auto content = static_cast(reply_->content_.get()); + object("giveaway_winners", JsonGiveawayWinners(content, client_)); + break; + } case td_api::messageStory::ID: object("story", JsonEmptyObject()); break; @@ -2728,8 +2770,11 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("giveaway", JsonGiveaway(content, client_)); break; } - case td_api::messagePremiumGiveawayWinners::ID: + case td_api::messagePremiumGiveawayWinners::ID: { + auto content = static_cast(message_->content.get()); + object("giveaway_winners", JsonGiveawayWinners(content, client_)); break; + } case td_api::messagePremiumGiveawayCompleted::ID: { auto content = static_cast(message_->content.get()); object("giveaway_completed", JsonGiveawayCompleted(content, message_->chat_id, client_)); @@ -11989,6 +12034,7 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr Date: Wed, 20 Dec 2023 17:35:18 +0300 Subject: [PATCH 36/55] Add "message_reaction" updates. --- telegram-bot-api/Client.cpp | 53 +++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 11 +++++--- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index ce40f68..d29998d 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3432,6 +3432,41 @@ class Client::JsonGameHighScore final : public td::Jsonable { const Client *client_; }; +class Client::JsonMessageReactionUpdated final : public td::Jsonable { + public: + JsonMessageReactionUpdated(const td_api::updateMessageReaction *update, const Client *client) + : update_(update), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("chat", JsonChat(update_->chat_id_, client_)); + object("message_id", as_client_message_id(update_->message_id_)); + switch (update_->actor_id_->get_id()) { + case td_api::messageSenderUser::ID: { + auto user_id = static_cast(update_->actor_id_.get())->user_id_; + object("user", JsonUser(user_id, client_)); + break; + } + case td_api::messageSenderChat::ID: { + auto actor_chat_id = static_cast(update_->actor_id_.get())->chat_id_; + object("actor_chat", JsonChat(actor_chat_id, client_)); + break; + } + default: + UNREACHABLE(); + } + object("date", update_->date_); + object("old_reaction", td::json_array(update_->old_reaction_types_, + [](const auto &reaction) { return JsonReactionType(reaction.get()); })); + object("new_reaction", td::json_array(update_->new_reaction_types_, + [](const auto &reaction) { return JsonReactionType(reaction.get()); })); + } + + private: + const td_api::updateMessageReaction *update_; + const Client *client_; +}; + class Client::JsonUpdateTypes final : public td::Jsonable { public: explicit JsonUpdateTypes(td::uint32 update_types) : update_types_(update_types) { @@ -6131,6 +6166,9 @@ void Client::on_update(object_ptr result) { case td_api::updateChatBoost::ID: add_update_chat_boost(move_object_as(result)); break; + case td_api::updateMessageReaction::ID: + add_update_message_reaction(move_object_as(result)); + break; case td_api::updateConnectionState::ID: { auto update = move_object_as(result); if (update->state_->get_id() == td_api::connectionStateReady::ID) { @@ -11675,6 +11713,8 @@ td::Slice Client::get_update_type_name(UpdateType update_type) { return td::Slice("chat_boost"); case UpdateType::ChatBoostRemoved: return td::Slice("removed_chat_boost"); + case UpdateType::MessageReaction: + return td::Slice("message_reaction"); default: UNREACHABLE(); return td::Slice(); @@ -11999,6 +12039,19 @@ void Client::add_update_chat_boost(object_ptr &&update) } } +void Client::add_update_message_reaction(object_ptr &&update) { + CHECK(update != nullptr); + auto left_time = update->date_ + 86400 - get_unix_time(); + if (left_time > 0) { + auto webhook_queue_id = update->chat_id_ + (static_cast(8) << 33); + add_update(UpdateType::MessageReaction, JsonMessageReactionUpdated(update.get(), this), left_time, + webhook_queue_id); + } else { + LOG(DEBUG) << "Skip updateMessageReaction with date " << update->date_ << ", because current date is " + << get_unix_time(); + } +} + td::int64 Client::choose_added_member_id(const td_api::messageChatAddMembers *message_add_members) const { CHECK(message_add_members != nullptr); for (auto &member_user_id : message_add_members->member_user_ids_) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 378db7a..21d918f 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -160,6 +160,7 @@ class Client final : public WebhookActor::Callback { class JsonForumTopicEdited; class JsonForumTopicInfo; class JsonGameHighScore; + class JsonMessageReactionUpdated; class JsonAddress; class JsonOrderInfo; class JsonSuccessfulPaymentBot; @@ -997,6 +998,8 @@ class Client final : public WebhookActor::Callback { void add_update_chat_boost(object_ptr &&update); + void add_update_message_reaction(object_ptr &&update); + // append only before Size enum class UpdateType : int32 { Message, @@ -1017,6 +1020,7 @@ class Client final : public WebhookActor::Callback { ChatJoinRequest, ChatBoostUpdated, ChatBoostRemoved, + MessageReaction, Size }; @@ -1046,9 +1050,10 @@ class Client final : public WebhookActor::Callback { bool have_message_access(int64 chat_id) const; - // by default ChatMember updates are disabled - static constexpr td::uint32 DEFAULT_ALLOWED_UPDATE_TYPES = - (1 << static_cast(UpdateType::Size)) - 1 - (1 << static_cast(UpdateType::ChatMember)); + // by default ChatMember and MessageReaction updates are disabled + static constexpr td::uint32 DEFAULT_ALLOWED_UPDATE_TYPES = (1 << static_cast(UpdateType::Size)) - 1 - + (1 << static_cast(UpdateType::ChatMember)) - + (1 << static_cast(UpdateType::MessageReaction)); object_ptr authorization_state_; bool was_authorized_ = false; From 56d2dc63929307830e4bb9b28b8744dab2364c1b Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 20 Dec 2023 17:45:26 +0300 Subject: [PATCH 37/55] Add "message_reaction_count" update. --- telegram-bot-api/Client.cpp | 51 +++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 14 +++++++--- 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index d29998d..22682d4 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -612,6 +612,20 @@ class Client::JsonReactionType final : public td::Jsonable { const td_api::ReactionType *reaction_type_; }; +class Client::JsonReactionCount final : public td::Jsonable { + public: + explicit JsonReactionCount(const td_api::messageReaction *message_reaction) : message_reaction_(message_reaction) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("type", JsonReactionType(message_reaction_->type_.get())); + object("total_count", message_reaction_->total_count_); + } + + private: + const td_api::messageReaction *message_reaction_; +}; + class Client::JsonChatPermissions final : public td::Jsonable { public: explicit JsonChatPermissions(const td_api::chatPermissions *chat_permissions) : chat_permissions_(chat_permissions) { @@ -3467,6 +3481,25 @@ class Client::JsonMessageReactionUpdated final : public td::Jsonable { const Client *client_; }; +class Client::JsonMessageReactionCountUpdated final : public td::Jsonable { + public: + JsonMessageReactionCountUpdated(const td_api::updateMessageReactions *update, const Client *client) + : update_(update), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("chat", JsonChat(update_->chat_id_, client_)); + object("message_id", as_client_message_id(update_->message_id_)); + object("date", update_->date_); + object("reactions", + td::json_array(update_->reactions_, [](const auto &reaction) { return JsonReactionCount(reaction.get()); })); + } + + private: + const td_api::updateMessageReactions *update_; + const Client *client_; +}; + class Client::JsonUpdateTypes final : public td::Jsonable { public: explicit JsonUpdateTypes(td::uint32 update_types) : update_types_(update_types) { @@ -6169,6 +6202,9 @@ void Client::on_update(object_ptr result) { case td_api::updateMessageReaction::ID: add_update_message_reaction(move_object_as(result)); break; + case td_api::updateMessageReactions::ID: + add_update_message_reaction_count(move_object_as(result)); + break; case td_api::updateConnectionState::ID: { auto update = move_object_as(result); if (update->state_->get_id() == td_api::connectionStateReady::ID) { @@ -11715,6 +11751,8 @@ td::Slice Client::get_update_type_name(UpdateType update_type) { return td::Slice("removed_chat_boost"); case UpdateType::MessageReaction: return td::Slice("message_reaction"); + case UpdateType::MessageReactionCount: + return td::Slice("message_reaction_count"); default: UNREACHABLE(); return td::Slice(); @@ -12052,6 +12090,19 @@ void Client::add_update_message_reaction(object_ptr &&update) { + CHECK(update != nullptr); + auto left_time = update->date_ + 86400 - get_unix_time(); + if (left_time > 0) { + auto webhook_queue_id = update->chat_id_ + (static_cast(9) << 33); + add_update(UpdateType::MessageReactionCount, JsonMessageReactionCountUpdated(update.get(), this), left_time, + webhook_queue_id); + } else { + LOG(DEBUG) << "Skip updateMessageReactions with date " << update->date_ << ", because current date is " + << get_unix_time(); + } +} + td::int64 Client::choose_added_member_id(const td_api::messageChatAddMembers *message_add_members) const { CHECK(message_add_members != nullptr); for (auto &member_user_id : message_add_members->member_user_ids_) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 21d918f..3b784f6 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -92,6 +92,7 @@ class Client final : public WebhookActor::Callback { class JsonUser; class JsonUsers; class JsonReactionType; + class JsonReactionCount; class JsonChatPermissions; class JsonChatPhotoInfo; class JsonChatLocation; @@ -161,6 +162,7 @@ class Client final : public WebhookActor::Callback { class JsonForumTopicInfo; class JsonGameHighScore; class JsonMessageReactionUpdated; + class JsonMessageReactionCountUpdated; class JsonAddress; class JsonOrderInfo; class JsonSuccessfulPaymentBot; @@ -1000,6 +1002,8 @@ class Client final : public WebhookActor::Callback { void add_update_message_reaction(object_ptr &&update); + void add_update_message_reaction_count(object_ptr &&update); + // append only before Size enum class UpdateType : int32 { Message, @@ -1021,6 +1025,7 @@ class Client final : public WebhookActor::Callback { ChatBoostUpdated, ChatBoostRemoved, MessageReaction, + MessageReactionCount, Size }; @@ -1050,10 +1055,11 @@ class Client final : public WebhookActor::Callback { bool have_message_access(int64 chat_id) const; - // by default ChatMember and MessageReaction updates are disabled - static constexpr td::uint32 DEFAULT_ALLOWED_UPDATE_TYPES = (1 << static_cast(UpdateType::Size)) - 1 - - (1 << static_cast(UpdateType::ChatMember)) - - (1 << static_cast(UpdateType::MessageReaction)); + // by default ChatMember, MessageReaction, and MessageReactionCount updates are disabled + static constexpr td::uint32 DEFAULT_ALLOWED_UPDATE_TYPES = + (1 << static_cast(UpdateType::Size)) - 1 - (1 << static_cast(UpdateType::ChatMember)) - + (1 << static_cast(UpdateType::MessageReaction)) - + (1 << static_cast(UpdateType::MessageReactionCount)); object_ptr authorization_state_; bool was_authorized_ = false; From 0ec870fd77a97da9a532a8c80add073c1a56d2fd Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 20 Dec 2023 17:57:39 +0300 Subject: [PATCH 38/55] Add setMessageReaction method. --- telegram-bot-api/Client.cpp | 64 +++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 5 +++ 2 files changed, 69 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 22682d4..c55af20 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -236,6 +236,7 @@ bool Client::init_methods() { 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("setmessagereaction", &Client::process_set_message_reaction_query); methods_.emplace("editmessagetext", &Client::process_edit_message_text_query); methods_.emplace("editmessagelivelocation", &Client::process_edit_message_live_location_query); methods_.emplace("stopmessagelivelocation", &Client::process_edit_message_live_location_query); @@ -8608,6 +8609,53 @@ td::Result> Client::get_poll_options(const Query *query) return std::move(options); } +td::Result> Client::get_reaction_type(td::JsonValue &&value) { + if (value.type() != td::JsonValue::Type::Object) { + return td::Status::Error(400, "expected an Object"); + } + + auto &object = value.get_object(); + + TRY_RESULT(type, object.get_required_string_field("type")); + if (type == "emoji") { + TRY_RESULT(emoji, object.get_required_string_field("emoji")); + return make_object(emoji); + } + if (type == "custom_emoji") { + TRY_RESULT(custom_emoji_id, object.get_required_long_field("custom_emoji_id")); + return make_object(custom_emoji_id); + } + return td::Status::Error(400, "invalid reaction type specified"); +} + +td::Result>> Client::get_reaction_types(const Query *query) { + auto types = query->arg("reaction"); + if (types.empty()) { + return td::vector>(); + } + LOG(INFO) << "Parsing JSON object: " << types; + auto r_value = json_decode(types); + if (r_value.is_error()) { + LOG(INFO) << "Can't parse JSON object: " << r_value.error(); + return td::Status::Error(400, "Can't parse reaction types JSON object"); + } + + auto value = r_value.move_as_ok(); + if (value.type() != td::JsonValue::Type::Array) { + return td::Status::Error(400, "Expected an Array of ReactionType"); + } + + td::vector> reaction_types; + for (auto &type : value.get_array()) { + auto r_reaction_type = get_reaction_type(std::move(type)); + if (r_reaction_type.is_error()) { + return td::Status::Error(400, PSLICE() << "Can't parse ReactionType: " << r_reaction_type.error().message()); + } + reaction_types.push_back(r_reaction_type.move_as_ok()); + } + return std::move(reaction_types); +} + td::int32 Client::get_integer_arg(const Query *query, td::Slice field_name, int32 default_value, int32 min_value, int32 max_value) { auto s_arg = query->arg(field_name); @@ -9438,6 +9486,22 @@ td::Status Client::process_send_chat_action_query(PromisedQueryPtr &query) { return td::Status::OK(); } +td::Status Client::process_set_message_reaction_query(PromisedQueryPtr &query) { + auto chat_id = query->arg("chat_id"); + auto message_id = get_message_id(query.get()); + auto is_big = to_bool(query->arg("is_big")); + TRY_RESULT(reaction_types, get_reaction_types(query.get())); + + check_message(chat_id, message_id, false, AccessRights::Read, "message to react", std::move(query), + [this, reaction_types = std::move(reaction_types), is_big](int64 chat_id, int64 message_id, + PromisedQueryPtr query) mutable { + send_request( + make_object(chat_id, message_id, std::move(reaction_types), is_big), + td::make_unique(std::move(query))); + }); + return td::Status::OK(); +} + td::Status Client::process_edit_message_text_query(PromisedQueryPtr &query) { TRY_RESULT(input_message_text, get_input_message_text(query.get())); auto chat_id = query->arg("chat_id"); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 3b784f6..57ea6a9 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -533,6 +533,10 @@ class Client final : public WebhookActor::Callback { static td::Result> get_poll_options(const Query *query); + static td::Result> get_reaction_type(td::JsonValue &&value); + + static td::Result>> get_reaction_types(const Query *query); + static int32 get_integer_arg(const Query *query, td::Slice field_name, int32 default_value, int32 min_value = std::numeric_limits::min(), int32 max_value = std::numeric_limits::max()); @@ -602,6 +606,7 @@ class Client final : public WebhookActor::Callback { 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_set_message_reaction_query(PromisedQueryPtr &query); td::Status process_edit_message_text_query(PromisedQueryPtr &query); td::Status process_edit_message_live_location_query(PromisedQueryPtr &query); td::Status process_edit_message_media_query(PromisedQueryPtr &query); From 047a3e9922926a7ab83e72053ecac51041f5beb7 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 21 Dec 2023 22:30:01 +0300 Subject: [PATCH 39/55] Support channel emoji status. --- telegram-bot-api/Client.cpp | 29 ++++++++++++++++++++--------- telegram-bot-api/Client.h | 4 ++-- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index c55af20..f614082 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -760,12 +760,6 @@ class Client::JsonChat final : public td::Jsonable { object("active_usernames", td::json_array(user_info->active_usernames, [](td::Slice username) { return td::JsonString(username); })); } - if (user_info->emoji_status_custom_emoji_id != 0) { - object("emoji_status_custom_emoji_id", td::to_string(user_info->emoji_status_custom_emoji_id)); - if (user_info->emoji_status_expiration_date != 0) { - object("emoji_status_expiration_date", user_info->emoji_status_expiration_date); - } - } if (!user_info->bio.empty()) { object("bio", user_info->bio); } @@ -922,6 +916,12 @@ class Client::JsonChat final : public td::Jsonable { if (chat_info->message_auto_delete_time != 0) { object("message_auto_delete_time", chat_info->message_auto_delete_time); } + if (chat_info->emoji_status_custom_emoji_id != 0) { + object("emoji_status_custom_emoji_id", td::to_string(chat_info->emoji_status_custom_emoji_id)); + if (chat_info->emoji_status_expiration_date != 0) { + object("emoji_status_expiration_date", chat_info->emoji_status_expiration_date); + } + } if (chat_info->available_reactions != nullptr) { object("available_reactions", td::json_array(chat_info->available_reactions->reactions_, @@ -5978,6 +5978,10 @@ void Client::on_update(object_ptr result) { chat_info->photo_info = std::move(chat->photo_); chat_info->permissions = std::move(chat->permissions_); chat_info->message_auto_delete_time = chat->message_auto_delete_time_; + chat_info->emoji_status_custom_emoji_id = + chat->emoji_status_ != nullptr ? chat->emoji_status_->custom_emoji_id_ : 0; + chat_info->emoji_status_expiration_date = + chat->emoji_status_ != nullptr ? chat->emoji_status_->expiration_date_ : 0; if (chat->available_reactions_->get_id() == td_api::chatAvailableReactionsSome::ID) { chat_info->available_reactions = move_object_as(chat->available_reactions_); } @@ -6016,6 +6020,16 @@ void Client::on_update(object_ptr result) { chat_info->message_auto_delete_time = update->message_auto_delete_time_; break; } + case td_api::updateChatEmojiStatus::ID: { + auto update = move_object_as(result); + auto chat_info = add_chat(update->chat_id_); + CHECK(chat_info->type != ChatInfo::Type::Unknown); + chat_info->emoji_status_custom_emoji_id = + update->emoji_status_ != nullptr ? update->emoji_status_->custom_emoji_id_ : 0; + chat_info->emoji_status_expiration_date = + update->emoji_status_ != nullptr ? update->emoji_status_->expiration_date_ : 0; + break; + } case td_api::updateChatAvailableReactions::ID: { auto update = move_object_as(result); auto chat_info = add_chat(update->chat_id_); @@ -11492,9 +11506,6 @@ void Client::add_user(UserInfo *user_info, object_ptr &&user) { user_info->editable_username = std::move(user->usernames_->editable_username_); } user_info->language_code = std::move(user->language_code_); - user_info->emoji_status_custom_emoji_id = user->emoji_status_ != nullptr ? user->emoji_status_->custom_emoji_id_ : 0; - user_info->emoji_status_expiration_date = user->emoji_status_ != nullptr ? user->emoji_status_->expiration_date_ : 0; - user_info->have_access = user->have_access_; user_info->is_premium = user->is_premium_; user_info->added_to_attachment_menu = user->added_to_attachment_menu_; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 57ea6a9..4169810 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -769,8 +769,6 @@ class Client final : public WebhookActor::Callback { td::vector active_usernames; td::string editable_username; td::string language_code; - int64 emoji_status_custom_emoji_id; - int32 emoji_status_expiration_date; object_ptr photo; td::string bio; @@ -833,6 +831,8 @@ class Client final : public WebhookActor::Callback { Type type = Type::Unknown; td::string title; int32 message_auto_delete_time = 0; + int64 emoji_status_custom_emoji_id = 0; + int32 emoji_status_expiration_date = 0; int32 accent_color_id = -1; int32 profile_accent_color_id = -1; int64 background_custom_emoji_id = 0; From 0fbcfa7ebae05a76bd3191541a1eab7da9e09622 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 22 Dec 2023 23:26:43 +0300 Subject: [PATCH 40/55] Support request_users.max_quantity. --- telegram-bot-api/Client.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index f614082..a76b0a4 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -6459,17 +6459,23 @@ td::Result> Client::get_keyboard_butt return make_object(text, make_object(url)); } - if (object.has_field("request_user")) { - TRY_RESULT(request_user, object.extract_required_field("request_user", td::JsonValue::Type::Object)); + if (object.has_field("request_user") || object.has_field("request_users")) { + td::JsonValue request_user; + if (object.has_field("request_users")) { + TRY_RESULT_ASSIGN(request_user, object.extract_required_field("request_users", td::JsonValue::Type::Object)); + } else { + TRY_RESULT_ASSIGN(request_user, object.extract_required_field("request_user", td::JsonValue::Type::Object)); + } auto &request_user_object = request_user.get_object(); TRY_RESULT(id, request_user_object.get_required_int_field("request_id")); auto restrict_user_is_bot = request_user_object.has_field("user_is_bot"); TRY_RESULT(user_is_bot, request_user_object.get_optional_bool_field("user_is_bot")); auto restrict_user_is_premium = request_user_object.has_field("user_is_premium"); TRY_RESULT(user_is_premium, request_user_object.get_optional_bool_field("user_is_premium")); + TRY_RESULT(max_quantity, request_user_object.get_optional_int_field("max_quantity", 1)); return make_object( - text, make_object(id, restrict_user_is_bot, user_is_bot, - restrict_user_is_premium, user_is_premium, 1)); + text, make_object( + id, restrict_user_is_bot, user_is_bot, restrict_user_is_premium, user_is_premium, max_quantity)); } if (object.has_field("request_chat")) { From ee59941ca3127d557df6279a06fbf566b59ea5e0 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 22 Dec 2023 23:32:52 +0300 Subject: [PATCH 41/55] Add Message.users_shared field. --- telegram-bot-api/Client.cpp | 19 ++++++++++++++++++- telegram-bot-api/Client.h | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index a76b0a4..8d18b59 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1964,6 +1964,20 @@ class Client::JsonUserShared final : public td::Jsonable { const td_api::messageUsersShared *users_shared_; }; +class Client::JsonUsersShared final : public td::Jsonable { + public: + explicit JsonUsersShared(const td_api::messageUsersShared *users_shared) : users_shared_(users_shared) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("user_ids", td::json_array(users_shared_->user_ids_, [](int64 user_id) { return user_id; })); + object("request_id", users_shared_->button_id_); + } + + private: + const td_api::messageUsersShared *users_shared_; +}; + class Client::JsonChatShared final : public td::Jsonable { public: explicit JsonChatShared(const td_api::messageChatShared *chat_shared) : chat_shared_(chat_shared) { @@ -2762,7 +2776,10 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { } case td_api::messageUsersShared::ID: { auto content = static_cast(message_->content.get()); - object("user_shared", JsonUserShared(content)); + if (content->user_ids_.size() == 1) { + object("user_shared", JsonUserShared(content)); + } + object("users_shared", JsonUsersShared(content)); break; } case td_api::messageChatShared::ID: { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 4169810..0a125ca 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -177,6 +177,7 @@ class Client final : public WebhookActor::Callback { class JsonChatSetMessageAutoDeleteTime; class JsonWriteAccessAllowed; class JsonUserShared; + class JsonUsersShared; class JsonChatShared; class JsonGiveaway; class JsonGiveawayWinners; From ade0841d41b7126c2d908475291a5e1cd8a1b905 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 28 Dec 2023 00:42:15 +0300 Subject: [PATCH 42/55] Update version to 7.0. --- CMakeLists.txt | 2 +- telegram-bot-api/telegram-bot-api.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b52e30d..994a060 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 6.9.2 LANGUAGES CXX) +project(TelegramBotApi VERSION 7.0 LANGUAGES CXX) if (POLICY CMP0069) option(TELEGRAM_BOT_API_ENABLE_LTO "Use \"ON\" to enable Link Time Optimization.") diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index ea0b469..04273fa 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -165,7 +165,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_ = "6.9.2"; + parameters->version_ = "7.0"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats(); From fc1de34374a20aa2e95c6578248f6e0d8b1f23b0 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 1 Jan 2024 17:47:09 +0300 Subject: [PATCH 43/55] Allow to pass empty ReplyParameters. --- telegram-bot-api/Client.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 8d18b59..35c4091 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -6418,6 +6418,9 @@ td::Result Client::get_reply_parameters(td::JsonVa return td::Status::Error(400, "Object expected as reply parameters"); } auto &object = value.get_object(); + if (object.field_count() == 0) { + return InputReplyParameters(); + } TRY_RESULT(chat_id, object.get_optional_string_field("chat_id")); TRY_RESULT(message_id, object.get_required_int_field("message_id")); TRY_RESULT(allow_sending_without_reply, object.get_optional_bool_field("allow_sending_without_reply")); From 4942b4346b5a0b2358583b0672b5ee9a133eac67 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 18 Jan 2024 14:34:05 +0300 Subject: [PATCH 44/55] Print log before dumping stack trace to avoid log overwriting by other threads. --- telegram-bot-api/telegram-bot-api.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index 04273fa..c1b5c92 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -103,6 +103,7 @@ static void dump_stacktrace_signal_handler(int sig) { static void fail_signal_handler(int sig) { has_failed = true; + print_log(); { td::LogGuard log_guard; td::signal_safe_write_signal_number(sig); @@ -110,7 +111,6 @@ static void fail_signal_handler(int sig) { options.use_gdb = true; td::Stacktrace::print_to_stderr(options); } - print_log(); _Exit(EXIT_FAILURE); } From 4639fbfb649e3521fdaf9466dd4207b696d34ff8 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 29 Jan 2024 02:03:25 +0300 Subject: [PATCH 45/55] Update TDLib to 1.8.24. --- td | 2 +- telegram-bot-api/Client.cpp | 54 ++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/td b/td index 27c3eae..983f669 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 27c3eaeb4964bd5f18d8488e354abde1a4383e49 +Subproject commit 983f669116b5e636b2cf92f8c1df3c5f2d073da2 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 35c4091..6e3e195 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2705,6 +2705,10 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { break; case td_api::messageExpiredVideo::ID: break; + case td_api::messageExpiredVideoNote::ID: + break; + case td_api::messageExpiredVoiceNote::ID: + break; case td_api::messageCustomServiceAction::ID: break; case td_api::messageChatSetTheme::ID: @@ -5051,6 +5055,7 @@ ServerBotInfo Client::get_bot_info() const { } void Client::start_up() { + CHECK(start_time_ < 1e-10); start_time_ = td::Time::now(); next_bot_updates_warning_time_ = start_time_ + 600; webhook_set_time_ = start_time_; @@ -5781,18 +5786,11 @@ void Client::on_update_authorization_state() { CHECK(authorization_state_ != nullptr); switch (authorization_state_->get_id()) { case td_api::authorizationStateWaitTdlibParameters::ID: { - send_request( - make_object("ignore_inline_thumbnails", make_object(true)), - td::make_unique()); - send_request(make_object("reuse_uploaded_photos_by_hash", - make_object(true)), - td::make_unique()); - send_request( - make_object("disable_network_statistics", make_object(true)), - td::make_unique()); - send_request(make_object("disable_time_adjustment_protection", - make_object(true)), - td::make_unique()); + for (td::string option : {"disable_network_statistics", "disable_time_adjustment_protection", "ignore_file_names", + "ignore_inline_thumbnails", "reuse_uploaded_photos_by_hash", "use_storage_optimizer"}) { + send_request(make_object(option, make_object(true)), + td::make_unique()); + } auto request = make_object(); request->use_test_dc_ = is_test_dc_; @@ -5806,8 +5804,6 @@ void Client::on_update_authorization_state() { request->system_language_code_ = "en"; request->device_model_ = "server"; request->application_version_ = parameters_->version_; - request->enable_storage_optimizer_ = true; - request->ignore_file_names_ = true; return send_request(std::move(request), td::make_unique(this)); } @@ -7480,8 +7476,8 @@ td::Result> Client::get_inlin } if (input_message_content == nullptr) { - input_message_content = make_object(nullptr, voice_note_duration, - "" /* waveform */, std::move(caption)); + input_message_content = make_object( + nullptr, voice_note_duration, "" /* waveform */, std::move(caption), nullptr); } return make_object( id, title, voice_note_url, voice_note_duration, std::move(reply_markup), std::move(input_message_content)); @@ -9220,9 +9216,9 @@ td::Status Client::process_send_video_note_query(PromisedQueryPtr &query) { auto thumbnail = get_input_thumbnail(query.get()); int32 duration = get_integer_arg(query.get(), "duration", 0, 0, MAX_DURATION); int32 length = get_integer_arg(query.get(), "length", 0, 0, MAX_LENGTH); - do_send_message( - make_object(std::move(video_note), std::move(thumbnail), duration, length), - std::move(query)); + do_send_message(make_object(std::move(video_note), std::move(thumbnail), duration, + length, nullptr), + std::move(query)); return td::Status::OK(); } @@ -9233,8 +9229,9 @@ td::Status Client::process_send_voice_query(PromisedQueryPtr &query) { } int32 duration = get_integer_arg(query.get(), "duration", 0, 0, MAX_DURATION); TRY_RESULT(caption, get_caption(query.get())); - do_send_message(make_object(std::move(voice_note), duration, "", std::move(caption)), - std::move(query)); + do_send_message( + make_object(std::move(voice_note), duration, "", std::move(caption), nullptr), + std::move(query)); return td::Status::OK(); } @@ -10488,7 +10485,7 @@ td::Status Client::process_restrict_chat_member_query(PromisedQueryPtr &query) { permissions->can_change_info_ = old_permissions->can_change_info_; permissions->can_invite_users_ = old_permissions->can_invite_users_; permissions->can_pin_messages_ = old_permissions->can_pin_messages_; - permissions->can_manage_topics_ = old_permissions->can_manage_topics_; + permissions->can_create_topics_ = old_permissions->can_create_topics_; } send_request(make_object( @@ -11809,7 +11806,7 @@ void Client::json_store_permissions(td::JsonObjectScope &object, const td_api::c object("can_change_info", td::JsonBool(permissions->can_change_info_)); object("can_invite_users", td::JsonBool(permissions->can_invite_users_)); object("can_pin_messages", td::JsonBool(permissions->can_pin_messages_)); - object("can_manage_topics", td::JsonBool(permissions->can_manage_topics_)); + object("can_manage_topics", td::JsonBool(permissions->can_create_topics_)); } td::Slice Client::get_update_type_name(UpdateType update_type) { @@ -12332,6 +12329,10 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr &&message, message_info->initial_send_date = message->forward_info_->date_; message_info->forward_origin = std::move(message->forward_info_->origin_); - auto from_chat_id = message->forward_info_->from_chat_id_; - message_info->is_automatic_forward = - from_chat_id != 0 && from_chat_id != chat_id && message->forward_info_->from_message_id_ != 0 && - get_chat_type(chat_id) == ChatType::Supergroup && get_chat_type(from_chat_id) == ChatType::Channel; + message_info->is_automatic_forward = message->forward_info_->source_ != nullptr && + get_chat_type(chat_id) == ChatType::Supergroup && + get_chat_type(message->forward_info_->source_->chat_id_) == ChatType::Channel; } else if (message->import_info_ != nullptr) { message_info->initial_send_date = message->import_info_->date_; message_info->forward_origin = make_object(message->import_info_->sender_name_); From f1b9eb8d4c618c86f31329eafbd899db74b4c0e6 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 14 Feb 2024 14:04:56 +0300 Subject: [PATCH 46/55] Update TDLib to 1.8.25. --- td | 2 +- telegram-bot-api/Client.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/td b/td index 983f669..d93a99e 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 983f669116b5e636b2cf92f8c1df3c5f2d073da2 +Subproject commit d93a99e3351db82573d765ce4f5e84714c277518 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 6e3e195..646c38f 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2816,6 +2816,8 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("giveaway_completed", JsonGiveawayCompleted(content, message_->chat_id, client_)); break; } + case td_api::messageChatBoost::ID: + break; default: UNREACHABLE(); } @@ -12347,6 +12349,8 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr Date: Wed, 14 Feb 2024 14:06:55 +0300 Subject: [PATCH 47/55] Make story management rights non-optional. --- telegram-bot-api/Client.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 646c38f..e0ace90 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -11782,11 +11782,9 @@ void Client::json_store_administrator_rights(td::JsonObjectScope &object, const } object("can_promote_members", td::JsonBool(rights->can_promote_members_)); object("can_manage_video_chats", td::JsonBool(rights->can_manage_video_chats_)); - if (chat_type == ChatType::Channel) { - object("can_post_stories", td::JsonBool(rights->can_post_stories_)); - object("can_edit_stories", td::JsonBool(rights->can_edit_stories_)); - object("can_delete_stories", td::JsonBool(rights->can_delete_stories_)); - } + object("can_post_stories", td::JsonBool(rights->can_post_stories_)); + object("can_edit_stories", td::JsonBool(rights->can_edit_stories_)); + object("can_delete_stories", td::JsonBool(rights->can_delete_stories_)); object("is_anonymous", td::JsonBool(rights->is_anonymous_)); } From d8c8291886c7ac292199b569bb79327f05a37e23 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 14 Feb 2024 16:59:22 +0300 Subject: [PATCH 48/55] Allow faster reopen for bots that were successfully authorized. --- telegram-bot-api/Client.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index e0ace90..413a3c1 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -6353,9 +6353,9 @@ void Client::finish_closing() { auto timeout = [&] { if (next_authorization_time_ <= 0.0) { - return 600.0; + return was_authorized_ && authorization_date_ < get_unix_time() - 1800 ? 1.0 : 1800.0; } - return td::min(next_authorization_time_ - td::Time::now(), 600.0); + return td::min(next_authorization_time_ - td::Time::now(), 1800.0); }(); set_timeout_in(timeout); LOG(INFO) << "Keep client opened for " << timeout << " seconds"; From 5da588afbeb490c45948eee7d06f7cfd54ce9024 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 14 Feb 2024 17:05:51 +0300 Subject: [PATCH 49/55] Don't reopen instance by "close" request. --- telegram-bot-api/ClientManager.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/telegram-bot-api/ClientManager.cpp b/telegram-bot-api/ClientManager.cpp index c47c25a..68338fd 100644 --- a/telegram-bot-api/ClientManager.cpp +++ b/telegram-bot-api/ClientManager.cpp @@ -90,6 +90,11 @@ void ClientManager::send(PromisedQueryPtr query) { auto id_it = token_to_id_.find(token); if (id_it == token_to_id_.end()) { + auto method = query->method(); + if (method == "close") { + return fail_query(400, "Bad Request: the bot has already been closed", std::move(query)); + } + td::string ip_address = query->get_peer_ip_address(); if (!ip_address.empty()) { td::IPAddress tmp; @@ -128,7 +133,6 @@ void ClientManager::send(PromisedQueryPtr query) { query->token().str(), query->is_test_dc(), tqueue_id, parameters_, client_info->stat_.actor_id(&client_info->stat_)); - auto method = query->method(); if (method != "deletewebhook" && method != "setwebhook") { auto bot_token_with_dc = PSTRING() << query->token() << (query->is_test_dc() ? ":T" : ""); auto webhook_info = parameters_->shared_data_->webhook_db_->get(bot_token_with_dc); From 75a2aae6b361b67e016645fa5debcb9e8b2ff7b6 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 14 Feb 2024 17:44:52 +0300 Subject: [PATCH 50/55] Support service messages about added boosts. --- telegram-bot-api/Client.cpp | 20 +++++++++++++++++--- telegram-bot-api/Client.h | 1 + 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 413a3c1..02b65fa 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2092,6 +2092,19 @@ class Client::JsonGiveawayCompleted final : public td::Jsonable { const Client *client_; }; +class Client::JsonChatBoostAdded final : public td::Jsonable { + public: + JsonChatBoostAdded(const td_api::messageChatBoost *chat_boost) : chat_boost_(chat_boost) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("boost_count", chat_boost_->boost_count_); + } + + private: + const td_api::messageChatBoost *chat_boost_; +}; + class Client::JsonWebAppInfo final : public td::Jsonable { public: explicit JsonWebAppInfo(const td::string &url) : url_(url) { @@ -2816,8 +2829,11 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("giveaway_completed", JsonGiveawayCompleted(content, message_->chat_id, client_)); break; } - case td_api::messageChatBoost::ID: + case td_api::messageChatBoost::ID: { + auto content = static_cast(message_->content.get()); + object("boost_added", JsonChatBoostAdded(content)); break; + } default: UNREACHABLE(); } @@ -12347,8 +12363,6 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr Date: Wed, 14 Feb 2024 17:53:10 +0300 Subject: [PATCH 51/55] Add Message.sender_boost_count. --- telegram-bot-api/Client.cpp | 4 ++++ telegram-bot-api/Client.h | 1 + 2 files changed, 5 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 02b65fa..193c7e2 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2396,6 +2396,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { if (!message_->author_signature.empty()) { object("author_signature", message_->author_signature); } + if (message_->sender_boost_count != 0) { + object("sender_boost_count", message_->sender_boost_count); + } if (message_->sender_chat_id != 0) { object("sender_chat", JsonChat(message_->sender_chat_id, client_)); } @@ -12810,6 +12813,7 @@ Client::FullMessageId Client::add_message(object_ptr &&message, message_info->can_be_saved = message->can_be_saved_; message_info->is_topic_message = message->is_topic_message_; message_info->author_signature = std::move(message->author_signature_); + message_info->sender_boost_count = message->sender_boost_count_; drop_internal_reply_to_message_in_another_chat(message); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 6f7fe52..1e860a3 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -867,6 +867,7 @@ class Client final : public WebhookActor::Callback { int32 date = 0; int32 edit_date = 0; int32 initial_send_date = 0; + int32 sender_boost_count = 0; object_ptr forward_origin; td::string author_signature; object_ptr reply_to_message; From 36b97bd5a78e6b0ece2539b6d66732412f9089c4 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 14 Feb 2024 18:16:48 +0300 Subject: [PATCH 52/55] Add Chat.unrestrict_boost_count. --- telegram-bot-api/Client.cpp | 4 ++++ telegram-bot-api/Client.h | 1 + 2 files changed, 5 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 193c7e2..4d891fc 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -860,6 +860,9 @@ class Client::JsonChat final : public td::Jsonable { if (supergroup_info->slow_mode_delay != 0) { object("slow_mode_delay", supergroup_info->slow_mode_delay); } + if (supergroup_info->unrestrict_boost_count != 0) { + object("unrestrict_boost_count", supergroup_info->unrestrict_boost_count); + } if (supergroup_info->linked_chat_id != 0) { object("linked_chat_id", supergroup_info->linked_chat_id); } @@ -6147,6 +6150,7 @@ void Client::on_update(object_ptr result) { supergroup_info->can_set_sticker_set = full_info->can_set_sticker_set_; supergroup_info->is_all_history_available = full_info->is_all_history_available_; supergroup_info->slow_mode_delay = full_info->slow_mode_delay_; + supergroup_info->unrestrict_boost_count = full_info->unrestrict_boost_count_; supergroup_info->linked_chat_id = full_info->linked_chat_id_; supergroup_info->location = std::move(full_info->location_); supergroup_info->has_hidden_members = full_info->has_hidden_members_; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 1e860a3..d206156 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -811,6 +811,7 @@ class Client final : public WebhookActor::Callback { int64 sticker_set_id = 0; int32 date = 0; int32 slow_mode_delay = 0; + int32 unrestrict_boost_count = 0; int64 linked_chat_id = 0; object_ptr location; object_ptr status; From c7adc690e4b8331c1b793f9791fc5077a828da0f Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 14 Feb 2024 18:43:33 +0300 Subject: [PATCH 53/55] Add chat and id fields to the class Story. --- telegram-bot-api/Client.cpp | 85 ++++++++++++++++++++++++++++++++++--- telegram-bot-api/Client.h | 3 ++ 2 files changed, 82 insertions(+), 6 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 4d891fc..c719f35 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -836,6 +836,14 @@ class Client::JsonChat final : public td::Jsonable { LOG(ERROR) << "Not found chat sticker set " << supergroup_info->sticker_set_id; } } + if (supergroup_info->custom_emoji_sticker_set_id != 0) { + auto sticker_set_name = client_->get_sticker_set_name(supergroup_info->custom_emoji_sticker_set_id); + if (!sticker_set_name.empty()) { + object("custom_emoji_sticker_set_name", sticker_set_name); + } else { + LOG(ERROR) << "Not found chat custom emoji sticker set " << supergroup_info->custom_emoji_sticker_set_id; + } + } if (supergroup_info->can_set_sticker_set) { object("can_set_sticker_set", td::JsonTrue()); } @@ -1605,6 +1613,23 @@ class Client::JsonPollAnswer final : public td::Jsonable { const Client *client_; }; +class Client::JsonStory final : public td::Jsonable { + public: + JsonStory(int64 chat_id, int32 story_id, const Client *client) + : chat_id_(chat_id), story_id_(story_id), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("chat", JsonChat(chat_id_, client_)); + object("id", story_id_); + } + + private: + int64 chat_id_; + int32 story_id_; + const Client *client_; +}; + class Client::JsonForumTopicCreated final : public td::Jsonable { public: explicit JsonForumTopicCreated(const td_api::messageForumTopicCreated *forum_topic_created) @@ -2810,9 +2835,11 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("chat_shared", JsonChatShared(content)); break; } - case td_api::messageStory::ID: - object("story", JsonEmptyObject()); + case td_api::messageStory::ID: { + auto content = static_cast(message_->content.get()); + object("story", JsonStory(content->story_sender_chat_id_, content->story_id_, client_)); break; + } case td_api::messageChatSetBackground::ID: break; case td_api::messagePremiumGiftCode::ID: @@ -4415,6 +4442,36 @@ class Client::TdOnGetStickerSetCallback final : public TdQueryCallback { int64 new_message_chat_id_; }; +class Client::TdOnGetChatCustomEmojiStickerSetCallback final : public TdQueryCallback { + public: + TdOnGetChatCustomEmojiStickerSetCallback(Client *client, int64 chat_id, int64 pinned_message_id, + PromisedQueryPtr query) + : client_(client), chat_id_(chat_id), pinned_message_id_(pinned_message_id), query_(std::move(query)) { + } + + void on_result(object_ptr result) final { + auto chat_info = client_->get_chat(chat_id_); + CHECK(chat_info != nullptr); + CHECK(chat_info->type == ChatInfo::Type::Supergroup); + auto supergroup_info = client_->add_supergroup_info(chat_info->supergroup_id); + if (result->get_id() == td_api::error::ID) { + supergroup_info->custom_emoji_sticker_set_id = 0; + } else { + CHECK(result->get_id() == td_api::stickerSet::ID); + auto sticker_set = move_object_as(result); + client_->on_get_sticker_set_name(sticker_set->id_, sticker_set->name_); + } + + answer_query(JsonChat(chat_id_, client_, true, pinned_message_id_), std::move(query_)); + } + + private: + Client *client_; + int64 chat_id_; + int64 pinned_message_id_; + PromisedQueryPtr query_; +}; + class Client::TdOnGetChatStickerSetCallback final : public TdQueryCallback { public: TdOnGetChatStickerSetCallback(Client *client, int64 chat_id, int64 pinned_message_id, PromisedQueryPtr query) @@ -4422,17 +4479,25 @@ class Client::TdOnGetChatStickerSetCallback final : public TdQueryCallback { } void on_result(object_ptr result) final { + auto chat_info = client_->get_chat(chat_id_); + CHECK(chat_info != nullptr); + CHECK(chat_info->type == ChatInfo::Type::Supergroup); + auto supergroup_info = client_->add_supergroup_info(chat_info->supergroup_id); if (result->get_id() == td_api::error::ID) { - auto chat_info = client_->get_chat(chat_id_); - CHECK(chat_info != nullptr); - CHECK(chat_info->type == ChatInfo::Type::Supergroup); - client_->add_supergroup_info(chat_info->supergroup_id)->sticker_set_id = 0; + supergroup_info->sticker_set_id = 0; } else { CHECK(result->get_id() == td_api::stickerSet::ID); auto sticker_set = move_object_as(result); client_->on_get_sticker_set_name(sticker_set->id_, sticker_set->name_); } + auto sticker_set_id = supergroup_info->custom_emoji_sticker_set_id; + if (sticker_set_id != 0 && client_->get_sticker_set_name(sticker_set_id).empty()) { + return client_->send_request(make_object(sticker_set_id), + td::make_unique( + client_, chat_id_, pinned_message_id_, std::move(query_))); + } + answer_query(JsonChat(chat_id_, client_, true, pinned_message_id_), std::move(query_)); } @@ -4478,6 +4543,13 @@ class Client::TdOnGetChatPinnedMessageCallback final : public TdQueryCallback { make_object(sticker_set_id), td::make_unique(client_, chat_id_, pinned_message_id, std::move(query_))); } + + sticker_set_id = supergroup_info->custom_emoji_sticker_set_id; + if (sticker_set_id != 0 && client_->get_sticker_set_name(sticker_set_id).empty()) { + return client_->send_request(make_object(sticker_set_id), + td::make_unique( + client_, chat_id_, pinned_message_id, std::move(query_))); + } } answer_query(JsonChat(chat_id_, client_, true, pinned_message_id), std::move(query_)); @@ -6147,6 +6219,7 @@ void Client::on_update(object_ptr result) { supergroup_info->invite_link = std::move( full_info->invite_link_ != nullptr ? std::move(full_info->invite_link_->invite_link_) : td::string()); supergroup_info->sticker_set_id = full_info->sticker_set_id_; + supergroup_info->custom_emoji_sticker_set_id = full_info->custom_emoji_sticker_set_id_; supergroup_info->can_set_sticker_set = full_info->can_set_sticker_set_; supergroup_info->is_all_history_available = full_info->is_all_history_available_; supergroup_info->slow_mode_delay = full_info->slow_mode_delay_; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index d206156..0b39eca 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -165,6 +165,7 @@ class Client final : public WebhookActor::Callback { class JsonMessageReactionCountUpdated; class JsonAddress; class JsonOrderInfo; + class JsonStory; class JsonSuccessfulPaymentBot; class JsonEncryptedPassportElement; class JsonEncryptedCredentials; @@ -214,6 +215,7 @@ class Client final : public WebhookActor::Callback { class TdOnGetMyShortDescriptionCallback; class TdOnGetChatFullInfoCallback; class TdOnGetChatStickerSetCallback; + class TdOnGetChatCustomEmojiStickerSetCallback; class TdOnGetChatPinnedMessageCallback; class TdOnGetChatPinnedMessageToUnpinCallback; class TdOnGetGroupMembersCallback; @@ -809,6 +811,7 @@ class Client final : public WebhookActor::Callback { td::string description; td::string invite_link; int64 sticker_set_id = 0; + int64 custom_emoji_sticker_set_id = 0; int32 date = 0; int32 slow_mode_delay = 0; int32 unrestrict_boost_count = 0; From 656152f1f1390bacf60da873e4ae7feafd30039d Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 15 Feb 2024 11:20:57 +0300 Subject: [PATCH 54/55] Add Message.reply_to_story. --- telegram-bot-api/Client.cpp | 9 +++++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 10 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index c719f35..07833f3 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2499,6 +2499,10 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { if (message_->reply_to_message != nullptr && message_->reply_to_message->quote_ != nullptr) { object("quote", JsonTextQuote(message_->reply_to_message->quote_.get(), client_)); } + if (message_->reply_to_story != nullptr) { + object("reply_to_story", + JsonStory(message_->reply_to_story->story_sender_chat_id_, message_->reply_to_story->story_id_, client_)); + } if (message_->media_album_id != 0) { object("media_group_id", td::to_string(message_->media_album_id)); } @@ -12899,6 +12903,11 @@ Client::FullMessageId Client::add_message(object_ptr &&message, } else { message_info->reply_to_message = nullptr; } + if (message->reply_to_ != nullptr && message->reply_to_->get_id() == td_api::messageReplyToStory::ID) { + message_info->reply_to_story = move_object_as(message->reply_to_); + } else { + message_info->reply_to_story = nullptr; + } if (message_info->content == nullptr || force_update_content) { message_info->content = std::move(message->content_); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 0b39eca..25f0cf8 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -875,6 +875,7 @@ class Client final : public WebhookActor::Callback { object_ptr forward_origin; td::string author_signature; object_ptr reply_to_message; + object_ptr reply_to_story; int64 media_album_id = 0; int64 via_bot_user_id = 0; object_ptr content; From 74f7c3a0cdd3cea66eb0e526f4086857dcdb03aa Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 16 Feb 2024 03:36:41 +0300 Subject: [PATCH 55/55] Update version to 7.1. --- CMakeLists.txt | 2 +- telegram-bot-api/telegram-bot-api.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 994a060..1f151b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 7.0 LANGUAGES CXX) +project(TelegramBotApi VERSION 7.1 LANGUAGES CXX) if (POLICY CMP0069) option(TELEGRAM_BOT_API_ENABLE_LTO "Use \"ON\" to enable Link Time Optimization.") diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index c1b5c92..5817ea7 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -165,7 +165,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_ = "7.0"; + parameters->version_ = "7.1"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats();