From 13d68879d31fa68a6654ab619a0c265f0c6df3df Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 9 Nov 2023 18:24:50 +0300 Subject: [PATCH 001/162] 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 002/162] 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 003/162] 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 004/162] 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 005/162] 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 006/162] 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 007/162] 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 008/162] 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 009/162] 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 010/162] 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 011/162] 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 012/162] 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 013/162] 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 014/162] 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 015/162] 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 016/162] 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 017/162] 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 018/162] 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 019/162] 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 020/162] 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 021/162] 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 022/162] 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 023/162] 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 024/162] 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 025/162] 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 026/162] 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 027/162] 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 028/162] 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 029/162] 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 030/162] 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 031/162] 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 032/162] 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 033/162] 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 034/162] 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 035/162] 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 036/162] 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 037/162] 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 038/162] 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 039/162] 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 040/162] 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 041/162] 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 042/162] 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 043/162] 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 044/162] 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 045/162] 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 046/162] 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 047/162] 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 048/162] 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 049/162] 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 050/162] 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 051/162] 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 052/162] 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 053/162] 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 054/162] 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 055/162] 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(); From 58c2f0165c894fa1a2e902fbd14ac3723729c8f1 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 8 Mar 2024 14:50:28 +0300 Subject: [PATCH 056/162] Update TDLib to 1.8.26. --- td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/td b/td index d93a99e..b3b63bb 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit d93a99e3351db82573d765ce4f5e84714c277518 +Subproject commit b3b63bbdc14dc377d2de6b78e5844fec1564f95d From a19b05e4ff50aac0239fa1ad4a9b973560d3e36d Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 11 Mar 2024 22:28:39 +0300 Subject: [PATCH 057/162] Fix warnings. --- telegram-bot-api/Client.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 07833f3..6979a86 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1078,8 +1078,8 @@ class Client::JsonMessages final : public td::Jsonable { 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) { + explicit JsonLinkPreviewOptions(const td_api::linkPreviewOptions *link_preview_options) + : link_preview_options_(link_preview_options) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); @@ -1102,7 +1102,6 @@ class Client::JsonLinkPreviewOptions final : public td::Jsonable { private: const td_api::linkPreviewOptions *link_preview_options_; - const Client *client_; }; class Client::JsonAnimation final : public td::Jsonable { @@ -2277,7 +2276,7 @@ class Client::JsonExternalReplyInfo final : public td::Jsonable { 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_)); + object("link_preview_options", JsonLinkPreviewOptions(content->link_preview_options_.get())); } break; } @@ -2514,7 +2513,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("entities", JsonVectorEntities(content->text_->entities_, client_)); } if (content->link_preview_options_ != nullptr) { - object("link_preview_options", JsonLinkPreviewOptions(content->link_preview_options_.get(), client_)); + object("link_preview_options", JsonLinkPreviewOptions(content->link_preview_options_.get())); } break; } @@ -6203,8 +6202,8 @@ void Client::on_update(object_ptr result) { 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()); + group_info->invite_link = + full_info->invite_link_ != nullptr ? std::move(full_info->invite_link_->invite_link_) : td::string(); break; } case td_api::updateSupergroup::ID: { @@ -6220,8 +6219,8 @@ void Client::on_update(object_ptr result) { 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->invite_link = + 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_; From de02ab0a009d76f83767ac7831ea235640b3b73b Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 14 Mar 2024 14:47:41 +0300 Subject: [PATCH 058/162] Update TDLib to 1.8.27. --- td | 2 +- telegram-bot-api/Client.cpp | 97 ++++++++++++++++++++++--------------- telegram-bot-api/Client.h | 6 +-- 3 files changed, 61 insertions(+), 44 deletions(-) diff --git a/td b/td index b3b63bb..efc6bd5 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit b3b63bbdc14dc377d2de6b78e5844fec1564f95d +Subproject commit efc6bd553b61dea0ae8c0436695e8d2539bf03f9 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 6979a86..423eaf9 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1983,7 +1983,7 @@ class Client::JsonUserShared final : public td::Jsonable { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("user_id", users_shared_->user_ids_[0]); + object("user_id", users_shared_->users_[0]->user_id_); object("request_id", users_shared_->button_id_); } @@ -1997,7 +1997,7 @@ class Client::JsonUsersShared final : public td::Jsonable { } 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("user_ids", td::json_array(users_shared_->users_, [](auto &user) { return user->user_id_; })); object("request_id", users_shared_->button_id_); } @@ -2011,7 +2011,7 @@ class Client::JsonChatShared final : public td::Jsonable { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("chat_id", chat_shared_->chat_id_); + object("chat_id", chat_shared_->chat_->chat_id_); object("request_id", chat_shared_->button_id_); } @@ -2827,7 +2827,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { } case td_api::messageUsersShared::ID: { auto content = static_cast(message_->content.get()); - if (content->user_ids_.size() == 1) { + if (content->users_.size() == 1) { object("user_shared", JsonUserShared(content)); } object("users_shared", JsonUsersShared(content)); @@ -3654,10 +3654,6 @@ class Client::JsonStickerSet final : public td::Jsonable { client_->json_store_thumbnail(object, sticker_set_->thumbnail_.get()); } - auto format = sticker_set_->sticker_format_->get_id(); - object("is_animated", td::JsonBool(format == td_api::stickerFormatTgs::ID)); - object("is_video", td::JsonBool(format == td_api::stickerFormatWebm::ID)); - auto type = Client::get_sticker_type(sticker_set_->sticker_type_); object("sticker_type", type); object("contains_masks", td::JsonBool(type == "mask")); @@ -6591,8 +6587,9 @@ td::Result> Client::get_keyboard_butt 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, max_quantity)); + text, make_object(id, restrict_user_is_bot, user_is_bot, + restrict_user_is_premium, user_is_premium, + max_quantity, false, false, false)); } if (object.has_field("request_chat")) { @@ -6621,7 +6618,7 @@ td::Result> Client::get_keyboard_butt text, make_object( id, chat_is_channel, restrict_chat_is_forum, chat_is_forum, restrict_chat_has_username, chat_has_username, chat_is_created, std::move(user_administrator_rights), - std::move(bot_administrator_rights), bot_is_member)); + std::move(bot_administrator_rights), bot_is_member, false, false, false)); } return make_object(text, nullptr); @@ -7918,11 +7915,15 @@ td::Result> Client::get_sticker_format if (sticker_format == "video") { return make_object(); } + if (sticker_format == "auto") { + return nullptr; + } return td::Status::Error(400, "Invalid sticker format specified"); } td::Result> Client::get_input_sticker(const Query *query, - td::JsonValue &&value) const { + td::JsonValue &&value, + td::Slice default_sticker_format) const { if (value.type() != td::JsonValue::Type::Object) { return td::Status::Error(400, "InputSticker must be an Object"); } @@ -7934,6 +7935,16 @@ td::Result> Client::get_input_sticker(c if (input_file == nullptr) { return td::Status::Error(400, "sticker not found"); } + td::string sticker_format_str; + if (default_sticker_format.empty()) { + TRY_RESULT_ASSIGN(sticker_format_str, object.get_required_string_field("format")); + } else { + TRY_RESULT_ASSIGN(sticker_format_str, object.get_optional_string_field("format")); + if (sticker_format_str.empty()) { + sticker_format_str = default_sticker_format.str(); + } + } + TRY_RESULT(sticker_format, get_sticker_format(sticker_format_str)); TRY_RESULT(emoji_list, object.extract_required_field("emoji_list", td::JsonValue::Type::Array)); TRY_RESULT(emojis, get_sticker_emojis(std::move(emoji_list))); TRY_RESULT(mask_position, get_mask_position(object.extract_field("mask_position"))); @@ -7947,8 +7958,8 @@ td::Result> Client::get_input_sticker(c input_keywords.push_back(keyword.get_string().str()); } } - return make_object(std::move(input_file), emojis, std::move(mask_position), - std::move(input_keywords)); + return make_object(std::move(input_file), std::move(sticker_format), emojis, + std::move(mask_position), std::move(input_keywords)); } td::Result> Client::get_input_sticker(const Query *query) const { @@ -7961,7 +7972,7 @@ td::Result> Client::get_input_sticker(c return td::Status::Error(400, "Can't parse sticker JSON object"); } - auto r_sticker = get_input_sticker(query, r_value.move_as_ok()); + auto r_sticker = get_input_sticker(query, r_value.move_as_ok(), "auto"); if (r_sticker.is_error()) { return td::Status::Error(400, PSLICE() << "Can't parse sticker: " << r_sticker.error().message()); } @@ -7971,14 +7982,20 @@ td::Result> Client::get_input_sticker(c auto emojis = query->arg("emojis"); auto sticker = get_input_file(query, "png_sticker"); + object_ptr sticker_format; object_ptr mask_position; if (sticker != nullptr) { + sticker_format = make_object(); TRY_RESULT_ASSIGN(mask_position, get_mask_position(query, "mask_position")); } else { sticker = get_input_file(query, "tgs_sticker", true); - if (sticker == nullptr) { + if (sticker != nullptr) { + sticker_format = make_object(); + } else { sticker = get_input_file(query, "webm_sticker", true); - if (sticker == nullptr) { + if (sticker != nullptr) { + sticker_format = make_object(); + } else { if (!query->arg("tgs_sticker").empty()) { return td::Status::Error(400, "Bad Request: animated sticker must be uploaded as an InputFile"); } @@ -7990,14 +8007,13 @@ td::Result> Client::get_input_sticker(c } } - return make_object(std::move(sticker), emojis.str(), std::move(mask_position), - td::vector()); + return make_object(std::move(sticker), std::move(sticker_format), emojis.str(), + std::move(mask_position), td::vector()); } -td::Result>> Client::get_input_stickers( - const Query *query, object_ptr &sticker_format) const { +td::Result>> Client::get_input_stickers(const Query *query) const { if (query->has_arg("stickers")) { - TRY_RESULT_ASSIGN(sticker_format, get_sticker_format(query->arg("sticker_format"))); + auto sticker_format_str = query->arg("sticker_format"); auto stickers = query->arg("stickers"); LOG(INFO) << "Parsing JSON object: " << stickers; auto r_value = json_decode(stickers); @@ -8018,7 +8034,7 @@ td::Result>> Client::get_inp td::vector> input_stickers; for (auto &input_sticker : value.get_array()) { - auto r_input_sticker = get_input_sticker(query, std::move(input_sticker)); + auto r_input_sticker = get_input_sticker(query, std::move(input_sticker), sticker_format_str); if (r_input_sticker.is_error()) { return td::Status::Error(400, PSLICE() << "Can't parse InputSticker: " << r_input_sticker.error().message()); } @@ -8030,6 +8046,7 @@ td::Result>> Client::get_inp auto emojis = query->arg("emojis"); auto sticker = get_input_file(query, "png_sticker"); + object_ptr sticker_format; object_ptr mask_position; if (sticker != nullptr) { sticker_format = make_object(); @@ -8055,8 +8072,8 @@ td::Result>> Client::get_inp } td::vector> stickers; - stickers.push_back(make_object(std::move(sticker), emojis.str(), std::move(mask_position), - td::vector())); + stickers.push_back(make_object(std::move(sticker), std::move(sticker_format), emojis.str(), + std::move(mask_position), td::vector())); return std::move(stickers); } @@ -9618,8 +9635,9 @@ td::Status Client::process_send_chat_action_query(PromisedQueryPtr &query) { check_chat(chat_id, AccessRights::Write, std::move(query), [this, message_thread_id, action = std::move(action)](int64 chat_id, PromisedQueryPtr query) mutable { - send_request(make_object(chat_id, message_thread_id, std::move(action)), - td::make_unique(std::move(query))); + send_request( + make_object(chat_id, message_thread_id, td::string(), std::move(action)), + td::make_unique(std::move(query))); }); return td::Status::OK(); } @@ -10781,23 +10799,21 @@ td::Status Client::process_create_new_sticker_set_query(PromisedQueryPtr &query) auto name = query->arg("name"); auto title = query->arg("title"); auto needs_repainting = to_bool(query->arg("needs_repainting")); - object_ptr sticker_format; - TRY_RESULT(stickers, get_input_stickers(query.get(), sticker_format)); + TRY_RESULT(stickers, get_input_stickers(query.get())); TRY_RESULT(sticker_type, get_sticker_type(query->arg("sticker_type"))); if (to_bool(query->arg("contains_masks"))) { sticker_type = make_object(); } - check_user( - user_id, std::move(query), - [this, user_id, title, name, sticker_format = std::move(sticker_format), sticker_type = std::move(sticker_type), - needs_repainting, stickers = std::move(stickers)](PromisedQueryPtr query) mutable { - send_request(make_object( - user_id, title.str(), name.str(), std::move(sticker_format), std::move(sticker_type), - needs_repainting, std::move(stickers), PSTRING() << "bot" << my_id_), - td::make_unique(this, false, std::move(query))); - }); + check_user(user_id, std::move(query), + [this, user_id, title, name, sticker_type = std::move(sticker_type), needs_repainting, + stickers = std::move(stickers)](PromisedQueryPtr query) mutable { + send_request(make_object(user_id, title.str(), name.str(), + std::move(sticker_type), needs_repainting, + std::move(stickers), PSTRING() << "bot" << my_id_), + td::make_unique(this, false, std::move(query))); + }); return td::Status::OK(); } @@ -10831,8 +10847,9 @@ td::Status Client::process_set_sticker_set_thumbnail_query(PromisedQueryPtr &que } check_user(user_id, std::move(query), [this, user_id, name, thumbnail = std::move(thumbnail)](PromisedQueryPtr query) mutable { - send_request(make_object(user_id, name.str(), std::move(thumbnail)), - td::make_unique(std::move(query))); + send_request( + make_object(user_id, name.str(), std::move(thumbnail), nullptr), + td::make_unique(std::move(query))); }); return td::Status::OK(); } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 25f0cf8..4c49c77 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -474,10 +474,10 @@ class Client final : public WebhookActor::Callback { td::Result> get_input_sticker(const Query *query) const; - td::Result> get_input_sticker(const Query *query, td::JsonValue &&value) const; + td::Result> get_input_sticker(const Query *query, td::JsonValue &&value, + td::Slice default_sticker_format) const; - td::Result>> get_input_stickers( - const Query *query, object_ptr &sticker_format) const; + td::Result>> get_input_stickers(const Query *query) const; static td::Result> get_sticker_input_file(const Query *query); From 393b6c00fb864aa6d4ca0c556140b8e7b6cb646e Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 14 Mar 2024 15:09:47 +0300 Subject: [PATCH 059/162] Add "business_connection" updates. --- telegram-bot-api/Client.cpp | 39 +++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 4 ++++ 2 files changed, 43 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 423eaf9..7cdd107 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3576,6 +3576,26 @@ class Client::JsonMessageReactionCountUpdated final : public td::Jsonable { const Client *client_; }; +class Client::JsonBusinessConnection final : public td::Jsonable { + public: + JsonBusinessConnection(const td_api::businessConnection *connection, const Client *client) + : connection_(connection), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("id", connection_->id_); + object("user", JsonUser(connection_->user_id_, client_)); + object("user_chat_id", connection_->user_chat_id_); + object("date", connection_->date_); + object("can_reply", td::JsonBool(connection_->can_reply_)); + object("is_enabled", td::JsonBool(connection_->is_enabled_)); + } + + private: + const td_api::businessConnection *connection_; + const Client *client_; +}; + class Client::JsonUpdateTypes final : public td::Jsonable { public: explicit JsonUpdateTypes(td::uint32 update_types) : update_types_(update_types) { @@ -6330,6 +6350,9 @@ void Client::on_update(object_ptr result) { case td_api::updateMessageReactions::ID: add_update_message_reaction_count(move_object_as(result)); break; + case td_api::updateBusinessConnection::ID: + add_update_business_connection(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) { @@ -11967,6 +11990,8 @@ td::Slice Client::get_update_type_name(UpdateType update_type) { return td::Slice("message_reaction"); case UpdateType::MessageReactionCount: return td::Slice("message_reaction_count"); + case UpdateType::BusinessConnection: + return td::Slice("business_connection"); default: UNREACHABLE(); return td::Slice(); @@ -12317,6 +12342,20 @@ void Client::add_update_message_reaction_count(object_ptr &&update) { + CHECK(update != nullptr); + auto connection = std::move(update->connection_); + auto left_time = connection->date_ + 86400 - get_unix_time(); + if (left_time > 0) { + auto webhook_queue_id = connection->user_id_ + (static_cast(10) << 33); + add_update(UpdateType::BusinessConnection, JsonBusinessConnection(connection.get(), this), left_time, + webhook_queue_id); + } else { + LOG(DEBUG) << "Skip updateBusinessConnection with date " << connection->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 4c49c77..0f2a1c6 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -163,6 +163,7 @@ class Client final : public WebhookActor::Callback { class JsonGameHighScore; class JsonMessageReactionUpdated; class JsonMessageReactionCountUpdated; + class JsonBusinessConnection; class JsonAddress; class JsonOrderInfo; class JsonStory; @@ -1017,6 +1018,8 @@ class Client final : public WebhookActor::Callback { void add_update_message_reaction_count(object_ptr &&update); + void add_update_business_connection(object_ptr &&update); + // append only before Size enum class UpdateType : int32 { Message, @@ -1039,6 +1042,7 @@ class Client final : public WebhookActor::Callback { ChatBoostRemoved, MessageReaction, MessageReactionCount, + BusinessConnection, Size }; From a3f62fcdf72f7b20a5ac0e7fa6c44f1ed1d9beb7 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 14 Mar 2024 15:44:44 +0300 Subject: [PATCH 060/162] Add cache for business connections. --- telegram-bot-api/Client.cpp | 31 ++++++++++++++++++++++++++----- telegram-bot-api/Client.h | 13 +++++++++++++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 7cdd107..e95a53c 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3578,7 +3578,7 @@ class Client::JsonMessageReactionCountUpdated final : public td::Jsonable { class Client::JsonBusinessConnection final : public td::Jsonable { public: - JsonBusinessConnection(const td_api::businessConnection *connection, const Client *client) + JsonBusinessConnection(const BusinessConnection *connection, const Client *client) : connection_(connection), client_(client) { } void store(td::JsonValueScope *scope) const { @@ -3592,7 +3592,7 @@ class Client::JsonBusinessConnection final : public td::Jsonable { } private: - const td_api::businessConnection *connection_; + const BusinessConnection *connection_; const Client *client_; }; @@ -11839,6 +11839,28 @@ td::string Client::get_chat_description(int64 chat_id) const { } } +const Client::BusinessConnection *Client::add_business_connection( + object_ptr &&business_connection, bool from_update) { + CHECK(business_connection != nullptr); + auto &connection = business_connections_[business_connection->id_]; + if (connection == nullptr) { + connection = td::make_unique(); + } else if (!from_update) { + return connection.get(); + } + connection->id_ = std::move(business_connection->id_); + connection->user_id_ = business_connection->user_id_; + connection->user_chat_id_ = business_connection->user_chat_id_; + connection->date_ = business_connection->date_; + connection->can_reply_ = business_connection->can_reply_; + connection->is_enabled_ = business_connection->is_enabled_; + return connection.get(); +} + +const Client::BusinessConnection *Client::get_business_connection(const td::string &connection_id) const { + return business_connections_.get_pointer(connection_id); +} + void Client::json_store_file(td::JsonObjectScope &object, const td_api::file *file, bool with_path) const { if (file->id_ == 0) { return; @@ -12344,12 +12366,11 @@ void Client::add_update_message_reaction_count(object_ptr &&update) { CHECK(update != nullptr); - auto connection = std::move(update->connection_); + const auto *connection = add_business_connection(std::move(update->connection_), true); auto left_time = connection->date_ + 86400 - get_unix_time(); if (left_time > 0) { auto webhook_queue_id = connection->user_id_ + (static_cast(10) << 33); - add_update(UpdateType::BusinessConnection, JsonBusinessConnection(connection.get(), this), left_time, - webhook_queue_id); + add_update(UpdateType::BusinessConnection, JsonBusinessConnection(connection, this), left_time, webhook_queue_id); } else { LOG(DEBUG) << "Skip updateBusinessConnection with date " << connection->date_ << ", because current date is " << get_unix_time(); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 0f2a1c6..cd34b49 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -888,6 +888,18 @@ class Client final : public WebhookActor::Callback { mutable bool is_content_changed = false; }; + struct BusinessConnection { + td::string id_; + int64 user_id_ = 0; + int64 user_chat_id_ = 0; + int32 date_ = 0; + bool can_reply_ = false; + bool is_enabled_ = false; + }; + const BusinessConnection *add_business_connection(object_ptr &&business_connection, + bool from_update); + const BusinessConnection *get_business_connection(const td::string &connection_id) const; + static int64 get_same_chat_reply_to_message_id(const td_api::messageReplyToMessage *reply_to, int64 message_thread_id); @@ -1112,6 +1124,7 @@ class Client final : public WebhookActor::Callback { td::WaitFreeHashMap> groups_; td::WaitFreeHashMap> supergroups_; td::WaitFreeHashMap> chats_; + td::WaitFreeHashMap> business_connections_; td::FlatHashMap> file_download_listeners_; td::FlatHashSet download_started_file_ids_; From a731cb0083a89dff537d4f7121886d03f2799dab Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 14 Mar 2024 16:09:23 +0300 Subject: [PATCH 061/162] Add Client::init_message. --- telegram-bot-api/Client.cpp | 13 +++++++++---- telegram-bot-api/Client.h | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index e95a53c..06ca775 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -12915,7 +12915,14 @@ Client::FullMessageId Client::add_message(object_ptr &&message, message_info = td::make_unique(); } - message_info->id = message_id; + init_message(message_info.get(), std::move(message), force_update_content); + + return {chat_id, message_id}; +} + +void Client::init_message(MessageInfo *message_info, object_ptr &&message, bool force_update_content) { + int64 chat_id = message->chat_id_; + message_info->id = message->id_; message_info->chat_id = chat_id; message_info->message_thread_id = message->message_thread_id_; message_info->date = message->date_; @@ -12997,11 +13004,9 @@ Client::FullMessageId Client::add_message(object_ptr &&message, } else if (message->content_->get_id() == td_api::messagePoll::ID) { message_info->content = std::move(message->content_); } - set_message_reply_markup(message_info.get(), std::move(message->reply_markup_)); + set_message_reply_markup(message_info, std::move(message->reply_markup_)); message = nullptr; - - return {chat_id, message_id}; } void Client::update_message_content(int64 chat_id, int64 message_id, object_ptr &&content) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index cd34b49..4fe12cc 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -924,7 +924,7 @@ class Client final : public WebhookActor::Callback { static bool are_equal_inline_keyboards(const td_api::replyMarkupInlineKeyboard *lhs, const td_api::replyMarkupInlineKeyboard *rhs); - void set_message_reply_markup(MessageInfo *message_info, object_ptr &&reply_markup); + static void set_message_reply_markup(MessageInfo *message_info, object_ptr &&reply_markup); static int64 get_sticker_set_id(const object_ptr &content); @@ -975,6 +975,7 @@ class Client final : public WebhookActor::Callback { }; FullMessageId add_message(object_ptr &&message, bool force_update_content = false); + void init_message(MessageInfo *message_info, object_ptr &&message, bool force_update_content); const MessageInfo *get_message(int64 chat_id, int64 message_id, bool force_cache) const; MessageInfo *get_message_editable(int64 chat_id, int64 message_id); From f05754481f5cb2cebd546cde2fc592db1a86d7da Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 14 Mar 2024 20:07:18 +0300 Subject: [PATCH 062/162] Support business_connection_id with sendChatAction. --- telegram-bot-api/Client.cpp | 74 +++++++++++++++++++++++++++++++++---- telegram-bot-api/Client.h | 8 ++++ 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 06ca775..2391314 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4012,7 +4012,7 @@ class Client::TdOnCheckUserCallback final : public TdQueryCallback { auto user_info = client_->get_user_info(user->id_); CHECK(user_info != nullptr); // it must have already been got through updates - return client_->check_user_read_access(user_info, std::move(query_), std::move(on_success_)); + client_->check_user_read_access(user_info, std::move(query_), std::move(on_success_)); } private: @@ -4063,7 +4063,7 @@ class Client::TdOnCheckChatCallback final : public TdQueryCallback { return fail_query(400, "Bad Request: chat not found", std::move(query_)); } - return client_->check_chat_access(chat->id_, access_rights_, chat_info, std::move(query_), std::move(on_success_)); + client_->check_chat_access(chat->id_, access_rights_, chat_info, std::move(query_), std::move(on_success_)); } private: @@ -4091,6 +4091,30 @@ class Client::TdOnCheckChatNoFailCallback final : public TdQueryCallback { OnSuccess on_success_; }; +template +class Client::TdOnCheckBusinessConnectionCallback final : public TdQueryCallback { + public: + TdOnCheckBusinessConnectionCallback(Client *client, PromisedQueryPtr query, OnSuccess on_success) + : client_(client), 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) { + return fail_query_with_error(std::move(query_), move_object_as(result), + "business connection not found"); + } + + CHECK(result->get_id() == td_api::businessConnection::ID); + auto connection = client_->add_business_connection(move_object_as(result), false); + on_success_(connection->id_, std::move(query_)); + } + + private: + Client *client_; + PromisedQueryPtr query_; + OnSuccess on_success_; +}; + template class Client::TdOnSearchStickerSetCallback final : public TdQueryCallback { public: @@ -4838,7 +4862,7 @@ class Client::TdOnGetSupergroupMemberCountCallback final : public TdQueryCallbac CHECK(result->get_id() == td_api::supergroupFullInfo::ID); auto supergroup_full_info = move_object_as(result); - return answer_query(td::VirtuallyJsonableInt(supergroup_full_info->member_count_), std::move(query_)); + answer_query(td::VirtuallyJsonableInt(supergroup_full_info->member_count_), std::move(query_)); } private: @@ -4857,7 +4881,7 @@ class Client::TdOnCreateInvoiceLinkCallback final : public TdQueryCallback { CHECK(result->get_id() == td_api::httpUrl::ID); auto http_url = move_object_as(result); - return answer_query(td::VirtuallyJsonableString(http_url->url_), std::move(query_)); + answer_query(td::VirtuallyJsonableString(http_url->url_), std::move(query_)); } private: @@ -4876,7 +4900,7 @@ class Client::TdOnReplacePrimaryChatInviteLinkCallback final : public TdQueryCal CHECK(result->get_id() == td_api::chatInviteLink::ID); auto invite_link = move_object_as(result); - return answer_query(td::VirtuallyJsonableString(invite_link->invite_link_), std::move(query_)); + answer_query(td::VirtuallyJsonableString(invite_link->invite_link_), std::move(query_)); } private: @@ -5525,6 +5549,30 @@ void Client::check_chat_no_fail(td::Slice chat_id_str, PromisedQueryPtr query, O chat_id, std::move(query), std::move(on_success))); } +td::Result Client::get_business_connection_chat_id(td::Slice chat_id_str) { + if (chat_id_str.empty()) { + return td::Status::Error(400, "Bad Request: chat_id is empty"); + } + + auto r_chat_id = td::to_integer_safe(chat_id_str); + if (r_chat_id.is_error()) { + return td::Status::Error(400, "Bad Request: chat_id must be a valid Integer"); + } + return r_chat_id.move_as_ok(); +} + +template +void Client::check_business_connection(const td::string &business_connection_id, PromisedQueryPtr query, + OnSuccess on_success) { + auto business_connection = get_business_connection(business_connection_id); + if (business_connection != nullptr) { + return on_success(business_connection_id, std::move(query)); + } + send_request( + make_object(business_connection_id), + td::make_unique>(this, std::move(query), std::move(on_success))); +} + template void Client::check_bot_command_scope(BotCommandScope &&scope, PromisedQueryPtr query, OnSuccess on_success) { CHECK(scope.scope_ != nullptr); @@ -9649,14 +9697,26 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { } td::Status Client::process_send_chat_action_query(PromisedQueryPtr &query) { - auto chat_id = query->arg("chat_id"); + auto chat_id_str = query->arg("chat_id"); auto message_thread_id = get_message_id(query.get(), "message_thread_id"); + auto business_connection_id = query->arg("business_connection_id").str(); object_ptr action = get_chat_action(query.get()); if (action == nullptr) { return td::Status::Error(400, "Wrong parameter action in request"); } + if (!business_connection_id.empty()) { + TRY_RESULT(chat_id, get_business_connection_chat_id(chat_id_str)); + check_business_connection( + business_connection_id, std::move(query), + [this, chat_id, action = std::move(action)](const td::string &business_connection_id, + PromisedQueryPtr query) mutable { + send_request(make_object(chat_id, 0, business_connection_id, std::move(action)), + td::make_unique(std::move(query))); + }); + return td::Status::OK(); + } - check_chat(chat_id, AccessRights::Write, std::move(query), + check_chat(chat_id_str, AccessRights::Write, std::move(query), [this, message_thread_id, action = std::move(action)](int64 chat_id, PromisedQueryPtr query) mutable { send_request( make_object(chat_id, message_thread_id, td::string(), std::move(action)), diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 4fe12cc..ae21af1 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -293,6 +293,8 @@ class Client final : public WebhookActor::Callback { template class TdOnCheckMessageThreadCallback; template + class TdOnCheckBusinessConnectionCallback; + template class TdOnCheckRemoteFileIdCallback; template class TdOnGetChatMemberCallback; @@ -321,6 +323,12 @@ class Client final : public WebhookActor::Callback { template void check_chat_no_fail(td::Slice chat_id_str, PromisedQueryPtr query, OnSuccess on_success); + static td::Result get_business_connection_chat_id(td::Slice chat_id_str); + + template + void check_business_connection(const td::string &business_connection_id, PromisedQueryPtr query, + OnSuccess on_success); + template void check_bot_command_scope(BotCommandScope &&scope, PromisedQueryPtr query, OnSuccess on_success); From 2ac6b4bcca9809635e8924ff5d160dd428b0fe6b Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 14 Mar 2024 22:51:02 +0300 Subject: [PATCH 063/162] Support sending messages to business connection. --- telegram-bot-api/Client.cpp | 74 +++++++++++++++++++++++++++++++++++-- telegram-bot-api/Client.h | 7 ++++ 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 2391314..1b298bc 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2416,6 +2416,9 @@ class Client::JsonTextQuote final : public td::Jsonable { void Client::JsonMessage::store(td::JsonValueScope *scope) const { CHECK(message_ != nullptr); auto object = scope->enter_object(); + if (!message_->business_connection_id.empty()) { + object("business_connection_id", message_->business_connection_id); + } object("message_id", as_client_message_id(message_->id)); if (message_->sender_user_id != 0) { object("from", JsonUser(message_->sender_user_id, client_)); @@ -3797,6 +3800,29 @@ class Client::TdOnSendMessageCallback final : public TdQueryCallback { PromisedQueryPtr query_; }; +class Client::TdOnSendBusinessMessageCallback final : public TdQueryCallback { + public: + TdOnSendBusinessMessageCallback(Client *client, td::string business_connection_id, PromisedQueryPtr query) + : client_(client), business_connection_id_(std::move(business_connection_id)), 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::businessMessage::ID); + auto message = client_->create_business_message(std::move(business_connection_id_), + move_object_as(result)); + answer_query(JsonMessage(message.get(), false, "sent business message", client_), std::move(query_)); + } + + private: + Client *client_; + td::string business_connection_id_; + PromisedQueryPtr query_; +}; + class Client::TdOnSendMessageAlbumCallback final : public TdQueryCallback { public: TdOnSendMessageAlbumCallback(Client *client, int64 chat_id, std::size_t message_count, PromisedQueryPtr query) @@ -6554,6 +6580,15 @@ td_api::object_ptr Client::get_input_message_reply_ return nullptr; } +td_api::object_ptr Client::get_input_message_reply_to( + InputReplyParameters &&reply_parameters) { + if (reply_parameters.reply_in_chat_id.empty() && reply_parameters.reply_to_message_id > 0) { + return make_object(0, reply_parameters.reply_to_message_id, + std::move(reply_parameters.quote)); + } + return nullptr; +} + td::Result Client::get_reply_parameters(const Query *query) { if (!query->has_arg("reply_parameters")) { InputReplyParameters result; @@ -11446,6 +11481,7 @@ 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 business_connection_id = query->arg("business_connection_id"); 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()); @@ -11461,9 +11497,30 @@ 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_parameters = std::move(reply_parameters), - disable_notification, protect_content, input_message_content = std::move(input_message_content)]( - object_ptr reply_markup, PromisedQueryPtr query) mutable { + [this, chat_id_str = chat_id.str(), message_thread_id, business_connection_id = business_connection_id.str(), + 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 { + if (!business_connection_id.empty()) { + auto r_chat_id = get_business_connection_chat_id(chat_id_str); + if (r_chat_id.is_error()) { + return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); + } + auto chat_id = r_chat_id.move_as_ok(); + return check_business_connection( + business_connection_id, std::move(query), + [this, chat_id, reply_parameters = std::move(reply_parameters), disable_notification, protect_content, + reply_markup = std::move(reply_markup), input_message_content = std::move(input_message_content)]( + const td::string &business_connection_id, PromisedQueryPtr query) mutable { + send_request( + make_object(business_connection_id, chat_id, + get_input_message_reply_to(std::move(reply_parameters)), + disable_notification, protect_content, + std::move(reply_markup), std::move(input_message_content)), + td::make_unique(this, business_connection_id, std::move(query))); + }); + } + 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, @@ -11481,7 +11538,7 @@ void Client::do_send_message(object_ptr input_messa 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), + check_reply_parameters(chat_id_str, std::move(reply_parameters), message_thread_id, std::move(query), std::move(on_success)); }); } @@ -13069,6 +13126,15 @@ void Client::init_message(MessageInfo *message_info, object_ptr message = nullptr; } +td::unique_ptr Client::create_business_message(td::string business_connection_id, + object_ptr &&message) { + auto message_info = td::make_unique(); + CHECK(message != nullptr); + init_message(message_info.get(), std::move(message->message_), true); + message_info->business_connection_id = std::move(business_connection_id); + return message_info; +} + void Client::update_message_content(int64 chat_id, int64 message_id, object_ptr &&content) { auto message_info = get_message_editable(chat_id, message_id); if (message_info == nullptr) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index ae21af1..d4c10a4 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -196,6 +196,7 @@ class Client final : public WebhookActor::Callback { class TdOnInitCallback; class TdOnGetUserProfilePhotosCallback; class TdOnSendMessageCallback; + class TdOnSendBusinessMessageCallback; class TdOnSendMessageAlbumCallback; class TdOnForwardMessagesCallback; class TdOnDeleteFailedToSendMessageCallback; @@ -383,6 +384,8 @@ class Client final : public WebhookActor::Callback { static object_ptr get_input_message_reply_to(CheckedReplyParameters &&reply_parameters); + static object_ptr get_input_message_reply_to(InputReplyParameters &&reply_parameters); + static td::Result get_reply_parameters(const Query *query); static td::Result get_reply_parameters(td::JsonValue &&value); @@ -889,6 +892,7 @@ class Client final : public WebhookActor::Callback { int64 via_bot_user_id = 0; object_ptr content; object_ptr reply_markup; + td::string business_connection_id; bool can_be_saved = false; bool is_automatic_forward = false; @@ -987,6 +991,9 @@ class Client final : public WebhookActor::Callback { const MessageInfo *get_message(int64 chat_id, int64 message_id, bool force_cache) const; MessageInfo *get_message_editable(int64 chat_id, int64 message_id); + td::unique_ptr create_business_message(td::string business_connection_id, + object_ptr &&message); + void update_message_content(int64 chat_id, int64 message_id, object_ptr &&content); void on_update_message_edited(int64 chat_id, int64 message_id, int32 edit_date, From 82134ecc94d8ebbc963a5755fde50b900790abd8 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 15 Mar 2024 15:56:40 +0300 Subject: [PATCH 064/162] Support sending media groups as business. --- telegram-bot-api/Client.cpp | 58 ++++++++++++++++++++++++++++++++++--- telegram-bot-api/Client.h | 1 + 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 1b298bc..7cf9d2d 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3853,6 +3853,34 @@ class Client::TdOnSendMessageAlbumCallback final : public TdQueryCallback { PromisedQueryPtr query_; }; +class Client::TdOnSendBusinessMessageAlbumCallback final : public TdQueryCallback { + public: + TdOnSendBusinessMessageAlbumCallback(Client *client, td::string business_connection_id, PromisedQueryPtr query) + : client_(client), business_connection_id_(std::move(business_connection_id)), 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::businessMessages::ID); + auto messages = move_object_as(result); + td::vector message_strings; + for (auto &message : messages->messages_) { + auto message_info = client_->create_business_message(business_connection_id_, std::move(message)); + message_strings.push_back( + td::json_encode(JsonMessage(message_info.get(), false, "sent business message", client_))); + } + answer_query(JsonMessages(message_strings), std::move(query_)); + } + + private: + Client *client_; + td::string business_connection_id_; + PromisedQueryPtr query_; +}; + class Client::TdOnForwardMessagesCallback final : public TdQueryCallback { public: TdOnForwardMessagesCallback(Client *client, int64 chat_id, std::size_t message_count, PromisedQueryPtr query) @@ -9696,6 +9724,7 @@ 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"); TRY_RESULT(reply_parameters, get_reply_parameters(query.get())); + auto business_connection_id = query->arg("business_connection_id"); 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_)); @@ -9704,9 +9733,30 @@ 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_parameters = std::move(reply_parameters), - disable_notification, protect_content, input_message_contents = std::move(input_message_contents)]( - object_ptr reply_markup, PromisedQueryPtr query) mutable { + [this, chat_id_str = chat_id.str(), message_thread_id, business_connection_id = business_connection_id.str(), + 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 { + if (!business_connection_id.empty()) { + auto r_chat_id = get_business_connection_chat_id(chat_id_str); + if (r_chat_id.is_error()) { + return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); + } + auto chat_id = r_chat_id.move_as_ok(); + return check_business_connection( + business_connection_id, std::move(query), + [this, chat_id, reply_parameters = std::move(reply_parameters), disable_notification, protect_content, + input_message_contents = std::move(input_message_contents), reply_markup = std::move(reply_markup)]( + const td::string &business_connection_id, PromisedQueryPtr query) mutable { + send_request( + make_object( + business_connection_id, chat_id, get_input_message_reply_to(std::move(reply_parameters)), + disable_notification, protect_content, std::move(input_message_contents)), + td::make_unique(this, business_connection_id, + std::move(query))); + }); + } + 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, @@ -9725,7 +9775,7 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { 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, std::move(reply_parameters), message_thread_id, std::move(query), + check_reply_parameters(chat_id_str, std::move(reply_parameters), message_thread_id, std::move(query), std::move(on_success)); }); return td::Status::OK(); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index d4c10a4..1b94cc7 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -198,6 +198,7 @@ class Client final : public WebhookActor::Callback { class TdOnSendMessageCallback; class TdOnSendBusinessMessageCallback; class TdOnSendMessageAlbumCallback; + class TdOnSendBusinessMessageAlbumCallback; class TdOnForwardMessagesCallback; class TdOnDeleteFailedToSendMessageCallback; class TdOnEditMessageCallback; From f6497b76c49bd5175679d5b22e63be8e32e5c011 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 11:21:43 +0300 Subject: [PATCH 065/162] Support replies in business messages. --- telegram-bot-api/Client.cpp | 17 +++++++++++++---- telegram-bot-api/Client.h | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 7cf9d2d..23e4e04 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2486,7 +2486,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { 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); + const MessageInfo *reply_to_message = !message_->business_connection_id.empty() + ? message_->business_reply_to_message.get() + : client_->get_message(message_->chat_id, reply_to_message_id, true); if (reply_to_message != nullptr) { object("reply_to_message", JsonMessage(reply_to_message, false, "reply in " + source_, client_)); } else { @@ -2719,7 +2721,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { auto content = static_cast(message_->content.get()); auto message_id = content->message_id_; if (message_id > 0) { - const MessageInfo *pinned_message = client_->get_message(message_->chat_id, message_id, true); + const MessageInfo *pinned_message = !message_->business_connection_id.empty() + ? message_->business_reply_to_message.get() + : client_->get_message(message_->chat_id, message_id, true); if (pinned_message != nullptr) { object("pinned_message", JsonMessage(pinned_message, false, "pin in " + source_, client_)); } else if (need_reply_) { @@ -3814,7 +3818,7 @@ class Client::TdOnSendBusinessMessageCallback final : public TdQueryCallback { CHECK(result->get_id() == td_api::businessMessage::ID); auto message = client_->create_business_message(std::move(business_connection_id_), move_object_as(result)); - answer_query(JsonMessage(message.get(), false, "sent business message", client_), std::move(query_)); + answer_query(JsonMessage(message.get(), true, "sent business message", client_), std::move(query_)); } private: @@ -3870,7 +3874,7 @@ class Client::TdOnSendBusinessMessageAlbumCallback final : public TdQueryCallbac for (auto &message : messages->messages_) { auto message_info = client_->create_business_message(business_connection_id_, std::move(message)); message_strings.push_back( - td::json_encode(JsonMessage(message_info.get(), false, "sent business message", client_))); + td::json_encode(JsonMessage(message_info.get(), true, "sent business message", client_))); } answer_query(JsonMessages(message_strings), std::move(query_)); } @@ -13182,6 +13186,11 @@ td::unique_ptr Client::create_business_message(td::string b CHECK(message != nullptr); init_message(message_info.get(), std::move(message->message_), true); message_info->business_connection_id = std::move(business_connection_id); + if (message->reply_to_message_ != nullptr) { + message_info->business_reply_to_message = td::make_unique(); + init_message(message_info->business_reply_to_message.get(), std::move(message->reply_to_message_), true); + message_info->business_reply_to_message->business_connection_id = message_info->business_connection_id; + } return message_info; } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 1b94cc7..ee7d7c6 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -887,6 +887,7 @@ class Client final : public WebhookActor::Callback { int32 sender_boost_count = 0; object_ptr forward_origin; td::string author_signature; + td::unique_ptr business_reply_to_message; object_ptr reply_to_message; object_ptr reply_to_story; int64 media_album_id = 0; From b9d4d5767862f51293b105ffdb4edaa6742ca2c9 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 11:54:29 +0300 Subject: [PATCH 066/162] Support business messages in need_skip_update_message. --- telegram-bot-api/Client.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 23e4e04..0edfad3 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -12562,9 +12562,17 @@ td::int64 Client::choose_added_member_id(const td_api::messageChatAddMembers *me } bool Client::need_skip_update_message(int64 chat_id, const object_ptr &message, bool is_edited) const { - auto chat = get_chat(chat_id); - CHECK(chat != nullptr); - if (message->is_outgoing_) { + const ChatInfo *chat; + ChatInfo::Type chat_type; + if (chat_id != 0) { + chat = get_chat(chat_id); + CHECK(chat != nullptr); + chat_type = chat->type; + } else { + chat = nullptr; + chat_type = ChatInfo::Type::Private; + } + if (message->is_outgoing_ && chat_id != 0) { switch (message->content_->get_id()) { case td_api::messageChatChangeTitle::ID: case td_api::messageChatChangePhoto::ID: @@ -12600,7 +12608,8 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptrtype == ChatInfo::Type::Supergroup) { + if (chat_type == ChatInfo::Type::Supergroup) { + CHECK(chat != nullptr); auto supergroup_info = get_supergroup_info(chat->supergroup_id); if (supergroup_info->status->get_id() == td_api::chatMemberStatusLeft::ID || supergroup_info->status->get_id() == td_api::chatMemberStatusBanned::ID) { @@ -12641,7 +12650,7 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptrtype != ChatInfo::Type::Supergroup) { + if (chat_type != ChatInfo::Type::Supergroup) { LOG(ERROR) << "Receive messageSupergroupChatCreate in the non-supergroup chat " << chat_id; return true; } @@ -12698,7 +12707,7 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptrid_, true); if (old_message != nullptr && !old_message->is_content_changed) { return true; From c783b1c821ba6c9d6d6c2fa0771e1aabaee0a875 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 12:36:19 +0300 Subject: [PATCH 067/162] Add "business_message" and "edited_business_message" updates. --- telegram-bot-api/Client.cpp | 121 ++++++++++++++++++++++++++++++++---- telegram-bot-api/Client.h | 23 +++++++ 2 files changed, 131 insertions(+), 13 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 0edfad3..3871a4c 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4513,11 +4513,13 @@ class Client::TdOnGetCallbackQueryMessageCallback final : public TdQueryCallback class Client::TdOnGetStickerSetCallback final : public TdQueryCallback { public: - TdOnGetStickerSetCallback(Client *client, int64 set_id, int64 new_callback_query_user_id, int64 new_message_chat_id) + TdOnGetStickerSetCallback(Client *client, int64 set_id, int64 new_callback_query_user_id, int64 new_message_chat_id, + const td::string &new_message_business_connection_id) : client_(client) , set_id_(set_id) , new_callback_query_user_id_(new_callback_query_user_id) - , new_message_chat_id_(new_message_chat_id) { + , new_message_chat_id_(new_message_chat_id) + , new_message_business_connection_id_(new_message_business_connection_id) { } void on_result(object_ptr result) final { @@ -4528,12 +4530,13 @@ class Client::TdOnGetStickerSetCallback final : public TdQueryCallback { << new_callback_query_user_id_ << "/new message in chat " << new_message_chat_id_ << ": " << td::oneline(to_string(error)); } - return client_->on_get_sticker_set(set_id_, new_callback_query_user_id_, new_message_chat_id_, nullptr); + return client_->on_get_sticker_set(set_id_, new_callback_query_user_id_, new_message_chat_id_, + new_message_business_connection_id_, nullptr); } CHECK(result->get_id() == td_api::stickerSet::ID); client_->on_get_sticker_set(set_id_, new_callback_query_user_id_, new_message_chat_id_, - move_object_as(result)); + new_message_business_connection_id_, move_object_as(result)); } private: @@ -4541,6 +4544,7 @@ class Client::TdOnGetStickerSetCallback final : public TdQueryCallback { int64 set_id_; int64 new_callback_query_user_id_; int64 new_message_chat_id_; + td::string new_message_business_connection_id_; }; class Client::TdOnGetChatCustomEmojiStickerSetCallback final : public TdQueryCallback { @@ -5422,6 +5426,7 @@ void Client::on_get_callback_query_message(object_ptr message, } void Client::on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, int64 new_message_chat_id, + const td::string &new_message_business_connection_id, object_ptr sticker_set) { if (new_callback_query_user_id != 0) { auto &queue = new_callback_query_queues_[new_callback_query_user_id]; @@ -5437,6 +5442,13 @@ void Client::on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, CHECK(!queue.queue_.empty()); } + if (!new_message_business_connection_id.empty()) { + auto &queue = new_business_message_queues_[new_message_business_connection_id]; + CHECK(queue.has_active_request_); + queue.has_active_request_ = false; + + CHECK(!queue.queue_.empty()); + } CHECK(set_id != 0); if (set_id != GREAT_MINDS_SET_ID) { @@ -5452,6 +5464,9 @@ void Client::on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, if (new_message_chat_id != 0) { process_new_message_queue(new_message_chat_id, 2); } + if (!new_message_business_connection_id.empty()) { + process_new_business_message_queue(new_message_business_connection_id); + } } void Client::on_get_sticker_set_name(int64 set_id, const td::string &name) { @@ -6459,6 +6474,12 @@ void Client::on_update(object_ptr result) { case td_api::updateBusinessConnection::ID: add_update_business_connection(move_object_as(result)); break; + case td_api::updateNewBusinessMessage::ID: + add_new_business_message(move_object_as(result)); + break; + case td_api::updateBusinessMessageEdited::ID: + add_business_message_edited(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) { @@ -12185,6 +12206,10 @@ td::Slice Client::get_update_type_name(UpdateType update_type) { return td::Slice("message_reaction_count"); case UpdateType::BusinessConnection: return td::Slice("business_connection"); + case UpdateType::BusinessMessage: + return td::Slice("business_message"); + case UpdateType::EditedBusinessMessage: + return td::Slice("edited_business_message"); default: UNREACHABLE(); return td::Slice(); @@ -12400,8 +12425,9 @@ void Client::process_new_callback_query_queue(int64 user_id, int state) { auto message_sticker_set_id = message_info == nullptr ? 0 : get_sticker_set_id(message_info->content); if (!have_sticker_set_name(message_sticker_set_id)) { queue.has_active_request_ = true; - return send_request(make_object(message_sticker_set_id), - td::make_unique(this, message_sticker_set_id, user_id, 0)); + return send_request( + make_object(message_sticker_set_id), + td::make_unique(this, message_sticker_set_id, user_id, 0, td::string())); } auto reply_to_message_id = get_same_chat_reply_to_message_id(message_info); if (reply_to_message_id > 0) { @@ -12410,8 +12436,9 @@ void Client::process_new_callback_query_queue(int64 user_id, int state) { reply_to_message_info == nullptr ? 0 : get_sticker_set_id(reply_to_message_info->content); if (!have_sticker_set_name(reply_sticker_set_id)) { queue.has_active_request_ = true; - return send_request(make_object(reply_sticker_set_id), - td::make_unique(this, reply_sticker_set_id, user_id, 0)); + return send_request( + make_object(reply_sticker_set_id), + td::make_unique(this, reply_sticker_set_id, user_id, 0, td::string())); } } } @@ -12548,6 +12575,20 @@ void Client::add_update_business_connection(object_ptr &&update) { + CHECK(update != nullptr); + CHECK(!update->connection_id_.empty()); + new_business_message_queues_[update->connection_id_].queue_.emplace(std::move(update->message_), false); + process_new_business_message_queue(update->connection_id_); +} + +void Client::add_business_message_edited(object_ptr &&update) { + CHECK(update != nullptr); + CHECK(!update->connection_id_.empty()); + new_business_message_queues_[update->connection_id_].queue_.emplace(std::move(update->message_), true); + process_new_business_message_queue(update->connection_id_); +} + 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_) { @@ -12780,6 +12821,7 @@ td::int64 Client::get_same_chat_reply_to_message_id(const MessageInfo *message_i } void Client::drop_internal_reply_to_message_in_another_chat(object_ptr &message) { + CHECK(message != nullptr); if (message->reply_to_ != nullptr && message->reply_to_->get_id() == td_api::messageReplyToMessage::ID) { auto *reply_to = static_cast(message->reply_to_.get()); auto reply_in_chat_id = reply_to->chat_id_; @@ -12969,8 +13011,9 @@ void Client::process_new_message_queue(int64 chat_id, int state) { auto message_sticker_set_id = get_sticker_set_id(message_ref->content_); if (!have_sticker_set_name(message_sticker_set_id)) { queue.has_active_request_ = true; - return send_request(make_object(message_sticker_set_id), - td::make_unique(this, message_sticker_set_id, 0, chat_id)); + return send_request( + make_object(message_sticker_set_id), + td::make_unique(this, message_sticker_set_id, 0, chat_id, td::string())); } if (reply_to_message_id > 0) { auto reply_to_message_info = get_message(chat_id, reply_to_message_id, true); @@ -12978,8 +13021,9 @@ void Client::process_new_message_queue(int64 chat_id, int state) { auto reply_sticker_set_id = get_sticker_set_id(reply_to_message_info->content); if (!have_sticker_set_name(reply_sticker_set_id)) { queue.has_active_request_ = true; - return send_request(make_object(reply_sticker_set_id), - td::make_unique(this, reply_sticker_set_id, 0, chat_id)); + return send_request( + make_object(reply_sticker_set_id), + td::make_unique(this, reply_sticker_set_id, 0, chat_id, td::string())); } } } @@ -13050,6 +13094,57 @@ void Client::process_new_message_queue(int64 chat_id, int state) { new_message_queues_.erase(chat_id); } +void Client::process_new_business_message_queue(const td::string &connection_id) { + auto &queue = new_business_message_queues_[connection_id]; + if (queue.has_active_request_) { + return; + } + if (logging_out_ || closing_) { + new_business_message_queues_.erase(connection_id); + return; + } + while (!queue.queue_.empty()) { + auto &message_ref = queue.queue_.front().message_; + + drop_internal_reply_to_message_in_another_chat(message_ref->message_); + + auto message_sticker_set_id = get_sticker_set_id(message_ref->message_->content_); + if (!have_sticker_set_name(message_sticker_set_id)) { + queue.has_active_request_ = true; + return send_request( + make_object(message_sticker_set_id), + td::make_unique(this, message_sticker_set_id, 0, 0, connection_id)); + } + if (message_ref->reply_to_message_ != nullptr) { + drop_internal_reply_to_message_in_another_chat(message_ref->reply_to_message_); + auto reply_sticker_set_id = get_sticker_set_id(message_ref->reply_to_message_->content_); + if (!have_sticker_set_name(reply_sticker_set_id)) { + queue.has_active_request_ = true; + return send_request( + make_object(reply_sticker_set_id), + td::make_unique(this, reply_sticker_set_id, 0, 0, connection_id)); + } + } + + auto message = std::move(message_ref); + auto is_edited = queue.queue_.front().is_edited_; + queue.queue_.pop(); + if (need_skip_update_message(0, message->message_, is_edited)) { + continue; + } + + auto message_date = message->message_->edit_date_ == 0 ? message->message_->date_ : message->message_->edit_date_; + auto now = get_unix_time(); + auto left_time = message_date + 86400 - now; + auto webhook_queue_id = message->message_->chat_id_ + (static_cast(11) << 33); + auto update_type = is_edited ? UpdateType::EditedBusinessMessage : UpdateType::BusinessMessage; + auto message_info = create_business_message(connection_id, std::move(message)); + add_update(update_type, JsonMessage(message_info.get(), true, get_update_type_name(update_type).str(), this), + left_time, webhook_queue_id); + } + new_business_message_queues_.erase(connection_id); +} + td::unique_ptr Client::delete_message(int64 chat_id, int64 message_id, bool only_from_cache) { auto message_info = std::move(messages_[{chat_id, message_id}]); if (message_info == nullptr) { @@ -13179,7 +13274,7 @@ void Client::init_message(MessageInfo *message_info, object_ptr auto sticker_set_id = get_sticker_set_id(message_info->content); if (!have_sticker_set_name(sticker_set_id)) { send_request(make_object(sticker_set_id), - td::make_unique(this, sticker_set_id, 0, 0)); + td::make_unique(this, sticker_set_id, 0, 0, td::string())); } } else if (message->content_->get_id() == td_api::messagePoll::ID) { message_info->content = std::move(message->content_); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index ee7d7c6..e4ceda8 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -245,6 +245,7 @@ class Client final : public WebhookActor::Callback { void on_get_callback_query_message(object_ptr message, int64 user_id, int state); void on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, int64 new_message_chat_id, + const td::string &new_message_business_connection_id, object_ptr sticker_set); void on_get_sticker_set_name(int64 set_id, const td::string &name); @@ -968,6 +969,12 @@ class Client final : public WebhookActor::Callback { void process_new_message_queue(int64 chat_id, int state); + void add_new_business_message(object_ptr &&update); + + void add_business_message_edited(object_ptr &&update); + + void process_new_business_message_queue(const td::string &connection_id); + struct FullMessageId { int64 chat_id; int64 message_id; @@ -1073,6 +1080,8 @@ class Client final : public WebhookActor::Callback { MessageReaction, MessageReactionCount, BusinessConnection, + BusinessMessage, + EditedBusinessMessage, Size }; @@ -1180,6 +1189,20 @@ class Client final : public WebhookActor::Callback { }; td::FlatHashMap new_message_queues_; // chat_id -> queue + struct NewBusinessMessage { + object_ptr message_; + bool is_edited_ = false; + + NewBusinessMessage(object_ptr &&message, bool is_edited) + : message_(std::move(message)), is_edited_(is_edited) { + } + }; + struct NewBusinessMessageQueue { + std::queue queue_; + bool has_active_request_ = false; + }; + td::FlatHashMap new_business_message_queues_; // connection_id -> queue + struct NewCallbackQueryQueue { std::queue> queue_; bool has_active_request_ = false; From 5bc529774616f6a81c814e4727ce7e9060d18800 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 12:52:17 +0300 Subject: [PATCH 068/162] Add Client::get_legacy_input_sticker. --- telegram-bot-api/Client.cpp | 36 ++++++------------------------------ telegram-bot-api/Client.h | 2 ++ 2 files changed, 8 insertions(+), 30 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 3871a4c..0dc2629 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -8138,8 +8138,11 @@ td::Result> Client::get_input_sticker(c return r_sticker.move_as_ok(); } - auto emojis = query->arg("emojis"); + return get_legacy_input_sticker(query); +} +td::Result> Client::get_legacy_input_sticker(const Query *query) const { + auto emojis = query->arg("emojis"); auto sticker = get_input_file(query, "png_sticker"); object_ptr sticker_format; object_ptr mask_position; @@ -8202,37 +8205,10 @@ td::Result>> Client::get_inp return std::move(input_stickers); } - auto emojis = query->arg("emojis"); - - auto sticker = get_input_file(query, "png_sticker"); - object_ptr sticker_format; - object_ptr mask_position; - if (sticker != nullptr) { - sticker_format = make_object(); - TRY_RESULT_ASSIGN(mask_position, get_mask_position(query, "mask_position")); - } else { - sticker = get_input_file(query, "tgs_sticker", true); - if (sticker != nullptr) { - sticker_format = make_object(); - } else { - sticker = get_input_file(query, "webm_sticker", true); - if (sticker != nullptr) { - sticker_format = make_object(); - } else { - if (!query->arg("tgs_sticker").empty()) { - return td::Status::Error(400, "Bad Request: animated sticker must be uploaded as an InputFile"); - } - if (!query->arg("webm_sticker").empty()) { - return td::Status::Error(400, "Bad Request: video sticker must be uploaded as an InputFile"); - } - return td::Status::Error(400, "Bad Request: there is no sticker file in the request"); - } - } - } + TRY_RESULT(input_sticker, get_legacy_input_sticker(query)); td::vector> stickers; - stickers.push_back(make_object(std::move(sticker), std::move(sticker_format), emojis.str(), - std::move(mask_position), td::vector())); + stickers.push_back(std::move(input_sticker)); return std::move(stickers); } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index e4ceda8..252e79e 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -486,6 +486,8 @@ class Client final : public WebhookActor::Callback { static td::Result> get_sticker_format(td::Slice sticker_format); + td::Result> get_legacy_input_sticker(const Query *query) const; + td::Result> get_input_sticker(const Query *query) const; td::Result> get_input_sticker(const Query *query, td::JsonValue &&value, From 538fc78fa68977a5a9e9a83a3e9829130e31e4ad Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 13:58:44 +0300 Subject: [PATCH 069/162] Add "deleted_business_messages" updates. --- telegram-bot-api/Client.cpp | 30 ++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 4 ++++ 2 files changed, 34 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 0dc2629..da6ffcf 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3603,6 +3603,24 @@ class Client::JsonBusinessConnection final : public td::Jsonable { const Client *client_; }; +class Client::JsonBusinessMessagesDeleted final : public td::Jsonable { + public: + JsonBusinessMessagesDeleted(const td_api::updateBusinessMessagesDeleted *update, const Client *client) + : update_(update), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("business_connection_id", update_->connection_id_); + object("chat", JsonChat(update_->chat_id_, client_)); + object("message_ids", + td::json_array(update_->message_ids_, [](int64 message_id) { return as_client_message_id(message_id); })); + } + + private: + const td_api::updateBusinessMessagesDeleted *update_; + const Client *client_; +}; + class Client::JsonUpdateTypes final : public td::Jsonable { public: explicit JsonUpdateTypes(td::uint32 update_types) : update_types_(update_types) { @@ -6480,6 +6498,9 @@ void Client::on_update(object_ptr result) { case td_api::updateBusinessMessageEdited::ID: add_business_message_edited(move_object_as(result)); break; + case td_api::updateBusinessMessagesDeleted::ID: + add_update_business_messages_deleted(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) { @@ -12186,6 +12207,8 @@ td::Slice Client::get_update_type_name(UpdateType update_type) { return td::Slice("business_message"); case UpdateType::EditedBusinessMessage: return td::Slice("edited_business_message"); + case UpdateType::BusinessMessagesDeleted: + return td::Slice("deleted_business_messages"); default: UNREACHABLE(); return td::Slice(); @@ -12551,6 +12574,13 @@ void Client::add_update_business_connection(object_ptr &&update) { + CHECK(update != nullptr); + auto webhook_queue_id = update->chat_id_ + (static_cast(11) << 33); + add_update(UpdateType::BusinessMessagesDeleted, JsonBusinessMessagesDeleted(update.get(), this), 86400, + webhook_queue_id); +} + void Client::add_new_business_message(object_ptr &&update) { CHECK(update != nullptr); CHECK(!update->connection_id_.empty()); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 252e79e..80a6a1b 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -164,6 +164,7 @@ class Client final : public WebhookActor::Callback { class JsonMessageReactionUpdated; class JsonMessageReactionCountUpdated; class JsonBusinessConnection; + class JsonBusinessMessagesDeleted; class JsonAddress; class JsonOrderInfo; class JsonStory; @@ -1059,6 +1060,8 @@ class Client final : public WebhookActor::Callback { void add_update_business_connection(object_ptr &&update); + void add_update_business_messages_deleted(object_ptr &&update); + // append only before Size enum class UpdateType : int32 { Message, @@ -1084,6 +1087,7 @@ class Client final : public WebhookActor::Callback { BusinessConnection, BusinessMessage, EditedBusinessMessage, + BusinessMessagesDeleted, Size }; From a872d6036200219bde798e91d7b86024492e7d99 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 14:17:05 +0300 Subject: [PATCH 070/162] Add setStickerSetThumbnail.format parameter. --- 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 da6ffcf..4ccc222 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -11035,11 +11035,17 @@ td::Status Client::process_set_sticker_set_thumbnail_query(PromisedQueryPtr &que if (thumbnail == nullptr) { thumbnail = get_input_file(query.get(), "thumb"); } + td::Slice sticker_format_str = query->arg("format"); + if (sticker_format_str.empty()) { + sticker_format_str = td::Slice("auto"); + } + TRY_RESULT(sticker_format, get_sticker_format(sticker_format_str)); check_user(user_id, std::move(query), - [this, user_id, name, thumbnail = std::move(thumbnail)](PromisedQueryPtr query) mutable { - send_request( - make_object(user_id, name.str(), std::move(thumbnail), nullptr), - td::make_unique(std::move(query))); + [this, user_id, name, thumbnail = std::move(thumbnail), + sticker_format = std::move(sticker_format)](PromisedQueryPtr query) mutable { + send_request(make_object(user_id, name.str(), std::move(thumbnail), + std::move(sticker_format)), + td::make_unique(std::move(query))); }); return td::Status::OK(); } From f1c14471850d1689b2cfcef8ed0c60699661bb38 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 14:26:39 +0300 Subject: [PATCH 071/162] Add chat.business_location field. --- telegram-bot-api/Client.cpp | 23 +++++++++++++++++++++++ telegram-bot-api/Client.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 4ccc222..47b1c43 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -627,6 +627,22 @@ class Client::JsonReactionCount final : public td::Jsonable { const td_api::messageReaction *message_reaction_; }; +class Client::JsonBusinessLocation final : public td::Jsonable { + public: + JsonBusinessLocation(const td_api::businessLocation *business_location) : business_location_(business_location) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + if (business_location_->location_ != nullptr) { + object("location", JsonLocation(business_location_->location_.get())); + } + object("address", business_location_->address_); + } + + private: + const td_api::businessLocation *business_location_; +}; + class Client::JsonChatPermissions final : public td::Jsonable { public: explicit JsonChatPermissions(const td_api::chatPermissions *chat_permissions) : chat_permissions_(chat_permissions) { @@ -769,6 +785,9 @@ class Client::JsonChat final : public td::Jsonable { if (user_info->has_restricted_voice_and_video_messages) { object("has_restricted_voice_and_video_messages", td::JsonTrue()); } + if (user_info->business_location != nullptr) { + object("business_location", JsonBusinessLocation(user_info->business_location.get())); + } } photo = user_info->photo.get(); break; @@ -6340,6 +6359,10 @@ void Client::on_update(object_ptr result) { 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->business_location = + full_info->business_info_ != nullptr && full_info->business_info_->location_ != nullptr + ? std::move(full_info->business_info_->location_) + : nullptr; 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; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 80a6a1b..619f006 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -93,6 +93,7 @@ class Client final : public WebhookActor::Callback { class JsonUsers; class JsonReactionType; class JsonReactionCount; + class JsonBusinessLocation; class JsonChatPermissions; class JsonChatPhotoInfo; class JsonChatLocation; @@ -793,6 +794,7 @@ class Client final : public WebhookActor::Callback { object_ptr photo; td::string bio; + object_ptr business_location; bool have_access = false; bool can_join_groups = false; From 1a86bb56db3829db240361ef3fcbb78fd1cf862e Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 17:04:42 +0300 Subject: [PATCH 072/162] Add chat.business_opening_hours field. --- telegram-bot-api/Client.cpp | 38 +++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 3 +++ 2 files changed, 41 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 47b1c43..25396d7 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -643,6 +643,37 @@ class Client::JsonBusinessLocation final : public td::Jsonable { const td_api::businessLocation *business_location_; }; +class Client::JsonBusinessOpeningHoursInterval final : public td::Jsonable { + public: + JsonBusinessOpeningHoursInterval(const td_api::businessOpeningHoursInterval *opening_hours_interval) + : opening_hours_interval_(opening_hours_interval) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("opening_minute", opening_hours_interval_->start_minute_); + object("closing_minute", opening_hours_interval_->end_minute_); + } + + private: + const td_api::businessOpeningHoursInterval *opening_hours_interval_; +}; + +class Client::JsonBusinessOpeningHours final : public td::Jsonable { + public: + JsonBusinessOpeningHours(const td_api::businessOpeningHours *opening_hours) : opening_hours_(opening_hours) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("opening_hours", td::json_array(opening_hours_->opening_hours_, [](const auto &opening_hours_interval) { + return JsonBusinessOpeningHoursInterval(opening_hours_interval.get()); + })); + object("time_zone_name", opening_hours_->time_zone_id_); + } + + private: + const td_api::businessOpeningHours *opening_hours_; +}; + class Client::JsonChatPermissions final : public td::Jsonable { public: explicit JsonChatPermissions(const td_api::chatPermissions *chat_permissions) : chat_permissions_(chat_permissions) { @@ -788,6 +819,9 @@ class Client::JsonChat final : public td::Jsonable { if (user_info->business_location != nullptr) { object("business_location", JsonBusinessLocation(user_info->business_location.get())); } + if (user_info->business_opening_hours != nullptr) { + object("business_opening_hours", JsonBusinessOpeningHours(user_info->business_opening_hours.get())); + } } photo = user_info->photo.get(); break; @@ -6363,6 +6397,10 @@ void Client::on_update(object_ptr result) { full_info->business_info_ != nullptr && full_info->business_info_->location_ != nullptr ? std::move(full_info->business_info_->location_) : nullptr; + user_info->business_opening_hours = + full_info->business_info_ != nullptr && full_info->business_info_->opening_hours_ != nullptr + ? std::move(full_info->business_info_->opening_hours_) + : nullptr; 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; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 619f006..8f1e259 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -94,6 +94,8 @@ class Client final : public WebhookActor::Callback { class JsonReactionType; class JsonReactionCount; class JsonBusinessLocation; + class JsonBusinessOpeningHoursInterval; + class JsonBusinessOpeningHours; class JsonChatPermissions; class JsonChatPhotoInfo; class JsonChatLocation; @@ -795,6 +797,7 @@ class Client final : public WebhookActor::Callback { object_ptr photo; td::string bio; object_ptr business_location; + object_ptr business_opening_hours; bool have_access = false; bool can_join_groups = false; From 15836d84f4a8834dc55f5203d53202069f6aa24a Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 17:50:16 +0300 Subject: [PATCH 073/162] Add Message.sender_business_bot. --- telegram-bot-api/Client.cpp | 6 ++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 7 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 25396d7..33ceb59 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2471,6 +2471,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); if (!message_->business_connection_id.empty()) { object("business_connection_id", message_->business_connection_id); + if (message_->sender_business_bot_user_id != 0) { + object("sender_business_bot", JsonUser(message_->sender_business_bot_user_id, client_)); + } } object("message_id", as_client_message_id(message_->id)); if (message_->sender_user_id != 0) { @@ -13361,10 +13364,13 @@ td::unique_ptr Client::create_business_message(td::string b object_ptr &&message) { auto message_info = td::make_unique(); CHECK(message != nullptr); + message_info->sender_business_bot_user_id = message->message_->sender_business_bot_user_id_; init_message(message_info.get(), std::move(message->message_), true); message_info->business_connection_id = std::move(business_connection_id); if (message->reply_to_message_ != nullptr) { message_info->business_reply_to_message = td::make_unique(); + message_info->business_reply_to_message->sender_business_bot_user_id = + message->reply_to_message_->sender_business_bot_user_id_; init_message(message_info->business_reply_to_message.get(), std::move(message->reply_to_message_), true); message_info->business_reply_to_message->business_connection_id = message_info->business_connection_id; } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 8f1e259..afc8d2e 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -904,6 +904,7 @@ class Client final : public WebhookActor::Callback { object_ptr content; object_ptr reply_markup; td::string business_connection_id; + int64 sender_business_bot_user_id = 0; bool can_be_saved = false; bool is_automatic_forward = false; From 5ca4a446f0cc4384de1a6fb37db718b5df4b282a Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 18:31:52 +0300 Subject: [PATCH 074/162] Add getBusinessConnection method. --- telegram-bot-api/Client.cpp | 12 ++++++++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 13 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 33ceb59..d49223b 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -257,6 +257,7 @@ bool Client::init_methods() { methods_.emplace("createchatinvitelink", &Client::process_create_chat_invite_link_query); methods_.emplace("editchatinvitelink", &Client::process_edit_chat_invite_link_query); methods_.emplace("revokechatinvitelink", &Client::process_revoke_chat_invite_link_query); + methods_.emplace("getbusinessconnection", &Client::process_get_business_connection_query); methods_.emplace("getchat", &Client::process_get_chat_query); methods_.emplace("setchatphoto", &Client::process_set_chat_photo_query); methods_.emplace("deletechatphoto", &Client::process_delete_chat_photo_query); @@ -10331,6 +10332,17 @@ td::Status Client::process_revoke_chat_invite_link_query(PromisedQueryPtr &query return td::Status::OK(); } +td::Status Client::process_get_business_connection_query(PromisedQueryPtr &query) { + auto business_connection_id = query->arg("business_connection_id"); + check_business_connection(business_connection_id.str(), std::move(query), + [this](const td::string &business_connection_id, PromisedQueryPtr query) mutable { + const auto *connection = get_business_connection(business_connection_id); + CHECK(connection != nullptr); + answer_query(JsonBusinessConnection(connection, this), std::move(query)); + }); + return td::Status::OK(); +} + td::Status Client::process_get_chat_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index afc8d2e..0e67436 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -650,6 +650,7 @@ class Client final : public WebhookActor::Callback { td::Status process_create_chat_invite_link_query(PromisedQueryPtr &query); td::Status process_edit_chat_invite_link_query(PromisedQueryPtr &query); td::Status process_revoke_chat_invite_link_query(PromisedQueryPtr &query); + td::Status process_get_business_connection_query(PromisedQueryPtr &query); td::Status process_get_chat_query(PromisedQueryPtr &query); td::Status process_set_chat_photo_query(PromisedQueryPtr &query); td::Status process_delete_chat_photo_query(PromisedQueryPtr &query); From 938847a51e65b8bc48d30d076496678d81238101 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 21:50:53 +0300 Subject: [PATCH 075/162] Pass BusinessConnection pointer to check_business_connection callback. --- telegram-bot-api/Client.cpp | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index d49223b..e873e86 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4239,7 +4239,7 @@ class Client::TdOnCheckBusinessConnectionCallback final : public TdQueryCallback CHECK(result->get_id() == td_api::businessConnection::ID); auto connection = client_->add_business_connection(move_object_as(result), false); - on_success_(connection->id_, std::move(query_)); + on_success_(connection, std::move(query_)); } private: @@ -5714,7 +5714,7 @@ void Client::check_business_connection(const td::string &business_connection_id, OnSuccess on_success) { auto business_connection = get_business_connection(business_connection_id); if (business_connection != nullptr) { - return on_success(business_connection_id, std::move(query)); + return on_success(business_connection, std::move(query)); } send_request( make_object(business_connection_id), @@ -9834,12 +9834,12 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { business_connection_id, std::move(query), [this, chat_id, reply_parameters = std::move(reply_parameters), disable_notification, protect_content, input_message_contents = std::move(input_message_contents), reply_markup = std::move(reply_markup)]( - const td::string &business_connection_id, PromisedQueryPtr query) mutable { + const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { send_request( make_object( - business_connection_id, chat_id, get_input_message_reply_to(std::move(reply_parameters)), + business_connection->id_, chat_id, get_input_message_reply_to(std::move(reply_parameters)), disable_notification, protect_content, std::move(input_message_contents)), - td::make_unique(this, business_connection_id, + td::make_unique(this, business_connection->id_, std::move(query))); }); } @@ -9880,9 +9880,9 @@ td::Status Client::process_send_chat_action_query(PromisedQueryPtr &query) { TRY_RESULT(chat_id, get_business_connection_chat_id(chat_id_str)); check_business_connection( business_connection_id, std::move(query), - [this, chat_id, action = std::move(action)](const td::string &business_connection_id, + [this, chat_id, action = std::move(action)](const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { - send_request(make_object(chat_id, 0, business_connection_id, std::move(action)), + send_request(make_object(chat_id, 0, business_connection->id_, std::move(action)), td::make_unique(std::move(query))); }); return td::Status::OK(); @@ -10335,10 +10335,8 @@ td::Status Client::process_revoke_chat_invite_link_query(PromisedQueryPtr &query td::Status Client::process_get_business_connection_query(PromisedQueryPtr &query) { auto business_connection_id = query->arg("business_connection_id"); check_business_connection(business_connection_id.str(), std::move(query), - [this](const td::string &business_connection_id, PromisedQueryPtr query) mutable { - const auto *connection = get_business_connection(business_connection_id); - CHECK(connection != nullptr); - answer_query(JsonBusinessConnection(connection, this), std::move(query)); + [this](const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { + answer_query(JsonBusinessConnection(business_connection, this), std::move(query)); }); return td::Status::OK(); } @@ -11665,13 +11663,13 @@ void Client::do_send_message(object_ptr input_messa business_connection_id, std::move(query), [this, chat_id, reply_parameters = std::move(reply_parameters), disable_notification, protect_content, reply_markup = std::move(reply_markup), input_message_content = std::move(input_message_content)]( - const td::string &business_connection_id, PromisedQueryPtr query) mutable { + const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { send_request( - make_object(business_connection_id, chat_id, + make_object(business_connection->id_, chat_id, get_input_message_reply_to(std::move(reply_parameters)), disable_notification, protect_content, std::move(reply_markup), std::move(input_message_content)), - td::make_unique(this, business_connection_id, std::move(query))); + td::make_unique(this, business_connection->id_, std::move(query))); }); } From 3d54e3c43bc91b154ae701c7dbe770ed70c40af5 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 19 Mar 2024 16:03:04 +0300 Subject: [PATCH 076/162] Add Chat.business_intro. --- telegram-bot-api/Client.cpp | 225 ++++++++++++++++++++---------------- telegram-bot-api/Client.h | 2 + 2 files changed, 129 insertions(+), 98 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index e873e86..f5a721a 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -552,6 +552,101 @@ class Client::JsonVectorEntities final : public td::Jsonable { const Client *client_; }; +class Client::JsonMaskPosition final : public td::Jsonable { + public: + explicit JsonMaskPosition(const td_api::maskPosition *mask_position) : mask_position_(mask_position) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("point", Client::MASK_POINTS[Client::mask_point_to_index(mask_position_->point_)]); + object("x_shift", mask_position_->x_shift_); + object("y_shift", mask_position_->y_shift_); + object("scale", mask_position_->scale_); + } + + private: + const td_api::maskPosition *mask_position_; +}; + +class Client::JsonSticker final : public td::Jsonable { + public: + JsonSticker(const td_api::sticker *sticker, const Client *client) : sticker_(sticker), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("width", sticker_->width_); + object("height", sticker_->height_); + if (!sticker_->emoji_.empty()) { + object("emoji", sticker_->emoji_); + } + auto set_name = client_->get_sticker_set_name(sticker_->set_id_); + if (!set_name.empty()) { + object("set_name", set_name); + } + + auto format = sticker_->format_->get_id(); + object("is_animated", td::JsonBool(format == td_api::stickerFormatTgs::ID)); + object("is_video", td::JsonBool(format == td_api::stickerFormatWebm::ID)); + + switch (sticker_->full_type_->get_id()) { + case td_api::stickerFullTypeRegular::ID: { + auto full_type = static_cast(sticker_->full_type_.get()); + object("type", Client::get_sticker_type(make_object())); + if (full_type->premium_animation_ != nullptr) { + object("premium_animation", JsonFile(full_type->premium_animation_.get(), client_, false)); + } + break; + } + case td_api::stickerFullTypeMask::ID: { + auto full_type = static_cast(sticker_->full_type_.get()); + object("type", Client::get_sticker_type(make_object())); + if (full_type->mask_position_ != nullptr) { + object("mask_position", JsonMaskPosition(full_type->mask_position_.get())); + } + break; + } + case td_api::stickerFullTypeCustomEmoji::ID: { + auto full_type = static_cast(sticker_->full_type_.get()); + object("type", Client::get_sticker_type(make_object())); + if (full_type->custom_emoji_id_ != 0) { + object("custom_emoji_id", td::to_string(full_type->custom_emoji_id_)); + } + if (full_type->needs_repainting_) { + object("needs_repainting", td::JsonBool(full_type->needs_repainting_)); + } + break; + } + default: + UNREACHABLE(); + break; + } + + client_->json_store_thumbnail(object, sticker_->thumbnail_.get()); + client_->json_store_file(object, sticker_->sticker_.get()); + } + + private: + const td_api::sticker *sticker_; + const Client *client_; +}; + +class Client::JsonStickers final : public td::Jsonable { + public: + JsonStickers(const td::vector> &stickers, const Client *client) + : stickers_(stickers), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto array = scope->enter_array(); + for (auto &sticker : stickers_) { + array << JsonSticker(sticker.get(), client_); + } + } + + private: + const td::vector> &stickers_; + const Client *client_; +}; + class Client::JsonLocation final : public td::Jsonable { public: explicit JsonLocation(const td_api::location *location, double expires_in = 0.0, int32 live_period = 0, @@ -628,9 +723,32 @@ class Client::JsonReactionCount final : public td::Jsonable { const td_api::messageReaction *message_reaction_; }; +class Client::JsonBusinessIntro final : public td::Jsonable { + public: + JsonBusinessIntro(const td_api::businessIntro *intro, const Client *client) : intro_(intro), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + if (!intro_->title_.empty()) { + object("title", intro_->title_); + } + if (!intro_->message_.empty()) { + object("message", intro_->message_); + } + if (intro_->sticker_ != nullptr) { + object("sticker", JsonSticker(intro_->sticker_.get(), client_)); + } + } + + private: + const td_api::businessIntro *intro_; + const Client *client_; +}; + class Client::JsonBusinessLocation final : public td::Jsonable { public: - JsonBusinessLocation(const td_api::businessLocation *business_location) : business_location_(business_location) { + explicit JsonBusinessLocation(const td_api::businessLocation *business_location) + : business_location_(business_location) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); @@ -646,7 +764,7 @@ class Client::JsonBusinessLocation final : public td::Jsonable { class Client::JsonBusinessOpeningHoursInterval final : public td::Jsonable { public: - JsonBusinessOpeningHoursInterval(const td_api::businessOpeningHoursInterval *opening_hours_interval) + explicit JsonBusinessOpeningHoursInterval(const td_api::businessOpeningHoursInterval *opening_hours_interval) : opening_hours_interval_(opening_hours_interval) { } void store(td::JsonValueScope *scope) const { @@ -661,7 +779,7 @@ class Client::JsonBusinessOpeningHoursInterval final : public td::Jsonable { class Client::JsonBusinessOpeningHours final : public td::Jsonable { public: - JsonBusinessOpeningHours(const td_api::businessOpeningHours *opening_hours) : opening_hours_(opening_hours) { + explicit JsonBusinessOpeningHours(const td_api::businessOpeningHours *opening_hours) : opening_hours_(opening_hours) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); @@ -817,6 +935,9 @@ class Client::JsonChat final : public td::Jsonable { if (user_info->has_restricted_voice_and_video_messages) { object("has_restricted_voice_and_video_messages", td::JsonTrue()); } + if (user_info->business_intro != nullptr) { + object("business_intro", JsonBusinessIntro(user_info->business_intro.get(), client_)); + } if (user_info->business_location != nullptr) { object("business_location", JsonBusinessLocation(user_info->business_location.get())); } @@ -1303,101 +1424,6 @@ class Client::JsonChatPhoto final : public td::Jsonable { const Client *client_; }; -class Client::JsonMaskPosition final : public td::Jsonable { - public: - explicit JsonMaskPosition(const td_api::maskPosition *mask_position) : mask_position_(mask_position) { - } - void store(td::JsonValueScope *scope) const { - auto object = scope->enter_object(); - object("point", Client::MASK_POINTS[Client::mask_point_to_index(mask_position_->point_)]); - object("x_shift", mask_position_->x_shift_); - object("y_shift", mask_position_->y_shift_); - object("scale", mask_position_->scale_); - } - - private: - const td_api::maskPosition *mask_position_; -}; - -class Client::JsonSticker final : public td::Jsonable { - public: - JsonSticker(const td_api::sticker *sticker, const Client *client) : sticker_(sticker), client_(client) { - } - void store(td::JsonValueScope *scope) const { - auto object = scope->enter_object(); - object("width", sticker_->width_); - object("height", sticker_->height_); - if (!sticker_->emoji_.empty()) { - object("emoji", sticker_->emoji_); - } - auto set_name = client_->get_sticker_set_name(sticker_->set_id_); - if (!set_name.empty()) { - object("set_name", set_name); - } - - auto format = sticker_->format_->get_id(); - object("is_animated", td::JsonBool(format == td_api::stickerFormatTgs::ID)); - object("is_video", td::JsonBool(format == td_api::stickerFormatWebm::ID)); - - switch (sticker_->full_type_->get_id()) { - case td_api::stickerFullTypeRegular::ID: { - auto full_type = static_cast(sticker_->full_type_.get()); - object("type", Client::get_sticker_type(make_object())); - if (full_type->premium_animation_ != nullptr) { - object("premium_animation", JsonFile(full_type->premium_animation_.get(), client_, false)); - } - break; - } - case td_api::stickerFullTypeMask::ID: { - auto full_type = static_cast(sticker_->full_type_.get()); - object("type", Client::get_sticker_type(make_object())); - if (full_type->mask_position_ != nullptr) { - object("mask_position", JsonMaskPosition(full_type->mask_position_.get())); - } - break; - } - case td_api::stickerFullTypeCustomEmoji::ID: { - auto full_type = static_cast(sticker_->full_type_.get()); - object("type", Client::get_sticker_type(make_object())); - if (full_type->custom_emoji_id_ != 0) { - object("custom_emoji_id", td::to_string(full_type->custom_emoji_id_)); - } - if (full_type->needs_repainting_) { - object("needs_repainting", td::JsonBool(full_type->needs_repainting_)); - } - break; - } - default: - UNREACHABLE(); - break; - } - - client_->json_store_thumbnail(object, sticker_->thumbnail_.get()); - client_->json_store_file(object, sticker_->sticker_.get()); - } - - private: - const td_api::sticker *sticker_; - const Client *client_; -}; - -class Client::JsonStickers final : public td::Jsonable { - public: - JsonStickers(const td::vector> &stickers, const Client *client) - : stickers_(stickers), client_(client) { - } - void store(td::JsonValueScope *scope) const { - auto array = scope->enter_array(); - for (auto &sticker : stickers_) { - array << JsonSticker(sticker.get(), client_); - } - } - - private: - const td::vector> &stickers_; - const Client *client_; -}; - class Client::JsonVideo final : public td::Jsonable { public: JsonVideo(const td_api::video *video, const Client *client) : video_(video), client_(client) { @@ -6397,6 +6423,9 @@ void Client::on_update(object_ptr result) { 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->business_intro = full_info->business_info_ != nullptr && full_info->business_info_->intro_ != nullptr + ? std::move(full_info->business_info_->intro_) + : nullptr; user_info->business_location = full_info->business_info_ != nullptr && full_info->business_info_->location_ != nullptr ? std::move(full_info->business_info_->location_) diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 0e67436..4b235f6 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -93,6 +93,7 @@ class Client final : public WebhookActor::Callback { class JsonUsers; class JsonReactionType; class JsonReactionCount; + class JsonBusinessIntro; class JsonBusinessLocation; class JsonBusinessOpeningHoursInterval; class JsonBusinessOpeningHours; @@ -797,6 +798,7 @@ class Client final : public WebhookActor::Callback { object_ptr photo; td::string bio; + object_ptr business_intro; object_ptr business_location; object_ptr business_opening_hours; From f8525043012d3561ad8fc16e5bfcf94e52f1db47 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 19 Mar 2024 16:07:43 +0300 Subject: [PATCH 077/162] Store td_api::businessInfo in UserInfo. --- telegram-bot-api/Client.cpp | 31 ++++++++++++------------------- telegram-bot-api/Client.h | 4 +--- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index f5a721a..8d132a7 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -935,14 +935,17 @@ class Client::JsonChat final : public td::Jsonable { if (user_info->has_restricted_voice_and_video_messages) { object("has_restricted_voice_and_video_messages", td::JsonTrue()); } - if (user_info->business_intro != nullptr) { - object("business_intro", JsonBusinessIntro(user_info->business_intro.get(), client_)); - } - if (user_info->business_location != nullptr) { - object("business_location", JsonBusinessLocation(user_info->business_location.get())); - } - if (user_info->business_opening_hours != nullptr) { - object("business_opening_hours", JsonBusinessOpeningHours(user_info->business_opening_hours.get())); + if (user_info->business_info != nullptr) { + auto business_info = user_info->business_info.get(); + if (business_info->intro_ != nullptr) { + object("business_intro", JsonBusinessIntro(business_info->intro_.get(), client_)); + } + if (business_info->location_ != nullptr) { + object("business_location", JsonBusinessLocation(business_info->location_.get())); + } + if (business_info->opening_hours_ != nullptr) { + object("business_opening_hours", JsonBusinessOpeningHours(business_info->opening_hours_.get())); + } } } photo = user_info->photo.get(); @@ -6423,17 +6426,7 @@ void Client::on_update(object_ptr result) { 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->business_intro = full_info->business_info_ != nullptr && full_info->business_info_->intro_ != nullptr - ? std::move(full_info->business_info_->intro_) - : nullptr; - user_info->business_location = - full_info->business_info_ != nullptr && full_info->business_info_->location_ != nullptr - ? std::move(full_info->business_info_->location_) - : nullptr; - user_info->business_opening_hours = - full_info->business_info_ != nullptr && full_info->business_info_->opening_hours_ != nullptr - ? std::move(full_info->business_info_->opening_hours_) - : nullptr; + user_info->business_info = std::move(full_info->business_info_); 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; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 4b235f6..6ddd4fb 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -798,9 +798,7 @@ class Client final : public WebhookActor::Callback { object_ptr photo; td::string bio; - object_ptr business_intro; - object_ptr business_location; - object_ptr business_opening_hours; + object_ptr business_info; bool have_access = false; bool can_join_groups = false; From 1adfc80566d00c09d0cf443aead0e3aab95446bd Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 19 Mar 2024 16:31:34 +0300 Subject: [PATCH 078/162] Resolve business intro sticker set. --- telegram-bot-api/Client.cpp | 48 +++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 49 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 8d132a7..da00ed9 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4681,6 +4681,39 @@ class Client::TdOnGetChatCustomEmojiStickerSetCallback final : public TdQueryCal PromisedQueryPtr query_; }; +class Client::TdOnGetChatBusinessIntroStickerSetCallback final : public TdQueryCallback { + public: + TdOnGetChatBusinessIntroStickerSetCallback(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::Private); + auto user_info = client_->add_user_info(chat_info->user_id); + if (result->get_id() == td_api::error::ID) { + if (user_info->business_info != nullptr && user_info->business_info->intro_ != nullptr && + user_info->business_info->intro_->sticker_ != nullptr) { + user_info->business_info->intro_->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) @@ -4759,6 +4792,21 @@ class Client::TdOnGetChatPinnedMessageCallback final : public TdQueryCallback { td::make_unique( client_, chat_id_, pinned_message_id, std::move(query_))); } + } else if (chat_info->type == ChatInfo::Type::Private) { + auto user_info = client_->get_user_info(chat_info->user_id); + CHECK(user_info != nullptr); + + if (user_info->business_info != nullptr && user_info->business_info->intro_ != nullptr) { + auto *sticker = user_info->business_info->intro_->sticker_.get(); + if (sticker != nullptr) { + auto sticker_set_id = 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_)); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 6ddd4fb..66b7f8c 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -224,6 +224,7 @@ class Client final : public WebhookActor::Callback { class TdOnGetChatFullInfoCallback; class TdOnGetChatStickerSetCallback; class TdOnGetChatCustomEmojiStickerSetCallback; + class TdOnGetChatBusinessIntroStickerSetCallback; class TdOnGetChatPinnedMessageCallback; class TdOnGetChatPinnedMessageToUnpinCallback; class TdOnGetGroupMembersCallback; From e327bbe8fe45125d72d476ff33b4ff0e806067c8 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 22 Mar 2024 13:03:48 +0300 Subject: [PATCH 079/162] Add Message.is_from_offline. --- 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 da00ed9..74d5c5b 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2978,6 +2978,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { if (message_->is_topic_message) { object("is_topic_message", td::JsonTrue()); } + if (message_->is_from_offline) { + object("is_from_offline", td::JsonTrue()); + } } class Client::JsonMessageId final : public td::Jsonable { @@ -13406,6 +13409,7 @@ void Client::init_message(MessageInfo *message_info, object_ptr } message_info->can_be_saved = message->can_be_saved_; + message_info->is_from_offline = message->is_from_offline_; 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_; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 66b7f8c..116998c 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -911,6 +911,7 @@ class Client final : public WebhookActor::Callback { bool can_be_saved = false; bool is_automatic_forward = false; bool is_topic_message = false; + bool is_from_offline = false; mutable bool is_content_changed = false; }; From d442d4b361e8cc4c5fd708deeab6ee844a1f8739 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 22 Mar 2024 13:34:26 +0300 Subject: [PATCH 080/162] Add UsersShared.users. --- telegram-bot-api/Client.cpp | 35 +++++++++++++++++++++++++++++++++-- telegram-bot-api/Client.h | 1 + 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 74d5c5b..a5d4935 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2074,18 +2074,49 @@ class Client::JsonUserShared final : public td::Jsonable { const td_api::messageUsersShared *users_shared_; }; +class Client::JsonSharedUser final : public td::Jsonable { + public: + JsonSharedUser(const td_api::sharedUser *shared_user, const Client *client) + : shared_user_(shared_user), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("user_id", shared_user_->user_id_); + if (!shared_user_->first_name_.empty()) { + object("first_name", shared_user_->first_name_); + } + if (!shared_user_->last_name_.empty()) { + object("last_name", shared_user_->last_name_); + } + if (!shared_user_->username_.empty()) { + object("username", shared_user_->username_); + } + if (shared_user_->photo_ != nullptr) { + object("photo", JsonPhoto(shared_user_->photo_.get(), client_)); + } + } + + private: + const td_api::sharedUser *shared_user_; + const Client *client_; +}; + class Client::JsonUsersShared final : public td::Jsonable { public: - explicit JsonUsersShared(const td_api::messageUsersShared *users_shared) : users_shared_(users_shared) { + JsonUsersShared(const td_api::messageUsersShared *users_shared, const Client *client) + : users_shared_(users_shared), client_(client) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); object("user_ids", td::json_array(users_shared_->users_, [](auto &user) { return user->user_id_; })); + object("users", td::json_array(users_shared_->users_, + [client = client_](auto &user) { return JsonSharedUser(user.get(), client); })); object("request_id", users_shared_->button_id_); } private: const td_api::messageUsersShared *users_shared_; + const Client *client_; }; class Client::JsonChatShared final : public td::Jsonable { @@ -2923,7 +2954,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { if (content->users_.size() == 1) { object("user_shared", JsonUserShared(content)); } - object("users_shared", JsonUsersShared(content)); + object("users_shared", JsonUsersShared(content, client_)); break; } case td_api::messageChatShared::ID: { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 116998c..9dba4fe 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -184,6 +184,7 @@ class Client final : public WebhookActor::Callback { class JsonChatSetMessageAutoDeleteTime; class JsonWriteAccessAllowed; class JsonUserShared; + class JsonSharedUser; class JsonUsersShared; class JsonChatShared; class JsonGiveaway; From e491a5a31dfb88ed8595e1535069e08835283678 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 22 Mar 2024 13:37:31 +0300 Subject: [PATCH 081/162] Add more fields to ChatShared. --- telegram-bot-api/Client.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index a5d4935..549e87d 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2121,16 +2121,28 @@ class Client::JsonUsersShared final : public td::Jsonable { class Client::JsonChatShared final : public td::Jsonable { public: - explicit JsonChatShared(const td_api::messageChatShared *chat_shared) : chat_shared_(chat_shared) { + JsonChatShared(const td_api::messageChatShared *chat_shared, const Client *client) + : chat_shared_(chat_shared), client_(client) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("chat_id", chat_shared_->chat_->chat_id_); + auto *shared_chat = chat_shared_->chat_.get(); + object("chat_id", shared_chat->chat_id_); + if (!shared_chat->title_.empty()) { + object("title", shared_chat->title_); + } + if (!shared_chat->username_.empty()) { + object("username", shared_chat->username_); + } + if (shared_chat->photo_ != nullptr) { + object("photo", JsonPhoto(shared_chat->photo_.get(), client_)); + } object("request_id", chat_shared_->button_id_); } private: const td_api::messageChatShared *chat_shared_; + const Client *client_; }; class Client::JsonGiveaway final : public td::Jsonable { @@ -2959,7 +2971,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { } case td_api::messageChatShared::ID: { auto content = static_cast(message_->content.get()); - object("chat_shared", JsonChatShared(content)); + object("chat_shared", JsonChatShared(content, client_)); break; } case td_api::messageStory::ID: { From e89489b1b26a8e3ae49c0fea9e88a3d98db549c7 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 22 Mar 2024 14:50:01 +0300 Subject: [PATCH 082/162] Support requesting of additional fields by keyboard buttons. --- telegram-bot-api/Client.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 549e87d..8c93de9 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -6947,10 +6947,13 @@ 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")); TRY_RESULT(max_quantity, request_user_object.get_optional_int_field("max_quantity", 1)); + TRY_RESULT(request_name, request_user_object.get_optional_bool_field("request_name")); + TRY_RESULT(request_username, request_user_object.get_optional_bool_field("request_username")); + TRY_RESULT(request_photo, request_user_object.get_optional_bool_field("request_photo")); return make_object( - text, make_object(id, restrict_user_is_bot, user_is_bot, - restrict_user_is_premium, user_is_premium, - max_quantity, false, false, false)); + text, make_object( + id, restrict_user_is_bot, user_is_bot, restrict_user_is_premium, user_is_premium, max_quantity, + request_name, request_username, request_photo)); } if (object.has_field("request_chat")) { @@ -6975,11 +6978,15 @@ td::Result> Client::get_keyboard_butt get_chat_administrator_rights(request_chat_object.extract_field("bot_administrator_rights"))); } TRY_RESULT(bot_is_member, request_chat_object.get_optional_bool_field("bot_is_member")); + TRY_RESULT(request_title, request_chat_object.get_optional_bool_field("request_title")); + TRY_RESULT(request_username, request_chat_object.get_optional_bool_field("request_username")); + TRY_RESULT(request_photo, request_chat_object.get_optional_bool_field("request_photo")); return make_object( - text, make_object( - id, chat_is_channel, restrict_chat_is_forum, chat_is_forum, restrict_chat_has_username, - chat_has_username, chat_is_created, std::move(user_administrator_rights), - std::move(bot_administrator_rights), bot_is_member, false, false, false)); + text, + make_object( + id, chat_is_channel, restrict_chat_is_forum, chat_is_forum, restrict_chat_has_username, chat_has_username, + chat_is_created, std::move(user_administrator_rights), std::move(bot_administrator_rights), bot_is_member, + request_title, request_username, request_photo)); } return make_object(text, nullptr); From f684e4c503929f8691f689459331d56ff48c80a3 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 22 Mar 2024 15:09:08 +0300 Subject: [PATCH 083/162] Add replaceStickerInSet. --- telegram-bot-api/Client.cpp | 22 ++++++++++++++++++++-- telegram-bot-api/Client.h | 4 +++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 8c93de9..47c5660 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -303,6 +303,7 @@ bool Client::init_methods() { methods_.emplace("uploadstickerfile", &Client::process_upload_sticker_file_query); methods_.emplace("createnewstickerset", &Client::process_create_new_sticker_set_query); methods_.emplace("addstickertoset", &Client::process_add_sticker_to_set_query); + methods_.emplace("replacestickerinset", &Client::process_replace_sticker_in_set_query); methods_.emplace("setstickersettitle", &Client::process_set_sticker_set_title_query); methods_.emplace("setstickersetthumb", &Client::process_set_sticker_set_thumbnail_query); methods_.emplace("setstickersetthumbnail", &Client::process_set_sticker_set_thumbnail_query); @@ -8421,8 +8422,9 @@ td::Result>> Client::get_inp return std::move(stickers); } -td::Result> Client::get_sticker_input_file(const Query *query) { - auto file_id = trim(query->arg("sticker")); +td::Result> Client::get_sticker_input_file(const Query *query, + td::Slice field_name) { + auto file_id = trim(query->arg(field_name)); if (file_id.empty()) { return td::Status::Error(400, "Sticker is not specified"); } @@ -11217,6 +11219,22 @@ td::Status Client::process_add_sticker_to_set_query(PromisedQueryPtr &query) { return td::Status::OK(); } +td::Status Client::process_replace_sticker_in_set_query(PromisedQueryPtr &query) { + TRY_RESULT(user_id, get_user_id(query.get())); + auto name = query->arg("name"); + TRY_RESULT(input_file, get_sticker_input_file(query.get(), "old_sticker")); + TRY_RESULT(sticker, get_input_sticker(query.get())); + + check_user(user_id, std::move(query), + [this, user_id, name, input_file = std::move(input_file), + sticker = std::move(sticker)](PromisedQueryPtr query) mutable { + send_request(make_object(user_id, name.str(), std::move(input_file), + std::move(sticker)), + td::make_unique(std::move(query))); + }); + return td::Status::OK(); +} + td::Status Client::process_set_sticker_set_title_query(PromisedQueryPtr &query) { auto name = query->arg("name"); auto title = query->arg("title"); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 9dba4fe..147629a 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -502,7 +502,8 @@ class Client final : public WebhookActor::Callback { td::Result>> get_input_stickers(const Query *query) const; - static td::Result> get_sticker_input_file(const Query *query); + static td::Result> get_sticker_input_file(const Query *query, + td::Slice field_name = "sticker"); static td::Result get_passport_element_hash(td::Slice encoded_hash); @@ -697,6 +698,7 @@ class Client final : public WebhookActor::Callback { td::Status process_upload_sticker_file_query(PromisedQueryPtr &query); td::Status process_create_new_sticker_set_query(PromisedQueryPtr &query); td::Status process_add_sticker_to_set_query(PromisedQueryPtr &query); + td::Status process_replace_sticker_in_set_query(PromisedQueryPtr &query); td::Status process_set_sticker_set_title_query(PromisedQueryPtr &query); td::Status process_set_sticker_set_thumbnail_query(PromisedQueryPtr &query); td::Status process_set_custom_emoji_sticker_set_thumbnail_query(PromisedQueryPtr &query); From f706d880553c5f0baedafd318f82746d333c1b7c Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 22 Mar 2024 15:26:22 +0300 Subject: [PATCH 084/162] Add Chat.birthdate. --- telegram-bot-api/Client.cpp | 21 +++++++++++++++++++++ telegram-bot-api/Client.h | 2 ++ 2 files changed, 23 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 47c5660..96477d6 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -724,6 +724,23 @@ class Client::JsonReactionCount final : public td::Jsonable { const td_api::messageReaction *message_reaction_; }; +class Client::JsonBirthdate final : public td::Jsonable { + public: + explicit JsonBirthdate(const td_api::birthdate *birthdate) : birthdate_(birthdate) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("day", birthdate_->day_); + object("month", birthdate_->month_); + if (birthdate_->year_ != 0) { + object("year", birthdate_->year_); + } + } + + private: + const td_api::birthdate *birthdate_; +}; + class Client::JsonBusinessIntro final : public td::Jsonable { public: JsonBusinessIntro(const td_api::businessIntro *intro, const Client *client) : intro_(intro), client_(client) { @@ -948,6 +965,9 @@ class Client::JsonChat final : public td::Jsonable { object("business_opening_hours", JsonBusinessOpeningHours(business_info->opening_hours_.get())); } } + if (user_info->birthdate != nullptr) { + object("birthdate", JsonBirthdate(user_info->birthdate.get())); + } } photo = user_info->photo.get(); break; @@ -6521,6 +6541,7 @@ void Client::on_update(object_ptr result) { 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->birthdate = std::move(full_info->birthdate_); user_info->business_info = std::move(full_info->business_info_); 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_; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 147629a..9c68403 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -93,6 +93,7 @@ class Client final : public WebhookActor::Callback { class JsonUsers; class JsonReactionType; class JsonReactionCount; + class JsonBirthdate; class JsonBusinessIntro; class JsonBusinessLocation; class JsonBusinessOpeningHoursInterval; @@ -802,6 +803,7 @@ class Client final : public WebhookActor::Callback { object_ptr photo; td::string bio; + object_ptr birthdate; object_ptr business_info; bool have_access = false; From 5f6e1a262f9595c6493812c0ee87c5c7be7d2144 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 28 Mar 2024 19:40:12 +0300 Subject: [PATCH 085/162] Add User.can_connect_to_business. --- telegram-bot-api/Client.cpp | 2 ++ telegram-bot-api/Client.h | 1 + 2 files changed, 3 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 96477d6..0dc572c 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -416,6 +416,7 @@ class Client::JsonUser final : public td::Jsonable { object("can_join_groups", td::JsonBool(user_info->can_join_groups)); object("can_read_all_group_messages", td::JsonBool(user_info->can_read_all_group_messages)); object("supports_inline_queries", td::JsonBool(user_info->is_inline_bot)); + object("can_connect_to_business", td::JsonBool(user_info->can_connect_to_business)); } } @@ -12115,6 +12116,7 @@ void Client::add_user(UserInfo *user_info, object_ptr &&user) { user_info->can_join_groups = bot->can_join_groups_; user_info->can_read_all_group_messages = bot->can_read_all_group_messages_; user_info->is_inline_bot = bot->is_inline_; + user_info->can_connect_to_business = bot->can_connect_to_business_; break; } case td_api::userTypeDeleted::ID: diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 9c68403..b1cc26a 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -809,6 +809,7 @@ class Client final : public WebhookActor::Callback { bool have_access = false; bool can_join_groups = false; bool can_read_all_group_messages = false; + bool can_connect_to_business = false; bool is_inline_bot = false; bool has_private_forwards = false; bool has_restricted_voice_and_video_messages = false; From c69178b2983c4769942c5dc1a6af8c2baa7424e9 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 28 Mar 2024 19:45:48 +0300 Subject: [PATCH 086/162] Add Chat.personal_chat. --- 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 0dc572c..01b1b46 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -969,6 +969,9 @@ class Client::JsonChat final : public td::Jsonable { if (user_info->birthdate != nullptr) { object("birthdate", JsonBirthdate(user_info->birthdate.get())); } + if (user_info->personal_chat_id != 0) { + object("personal_chat", JsonChat(user_info->personal_chat_id, client_)); + } } photo = user_info->photo.get(); break; @@ -6544,6 +6547,7 @@ void Client::on_update(object_ptr result) { user_info->bio = full_info->bio_ != nullptr ? std::move(full_info->bio_->text_) : td::string(); user_info->birthdate = std::move(full_info->birthdate_); user_info->business_info = std::move(full_info->business_info_); + user_info->personal_chat_id = full_info->personal_chat_id_; 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; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index b1cc26a..f53b8e1 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -805,6 +805,7 @@ class Client final : public WebhookActor::Callback { td::string bio; object_ptr birthdate; object_ptr business_info; + int64 personal_chat_id = 0; bool have_access = false; bool can_join_groups = false; From 6173126371aa7a8d7cf7974d2b00cde22369e51f Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 31 Mar 2024 19:26:26 +0300 Subject: [PATCH 087/162] Update version to 7.2. --- 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 1f151b7..1028fe4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 7.1 LANGUAGES CXX) +project(TelegramBotApi VERSION 7.2 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 5817ea7..97b8fe7 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.1"; + parameters->version_ = "7.2"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats(); From b56b61ba0e12d730fb777771a0dd7590b05c271d Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 21 Apr 2024 22:04:27 +0300 Subject: [PATCH 088/162] Update TDLib to 1.8.28. --- td | 2 +- telegram-bot-api/Client.cpp | 41 +++++++++++++++++++------------------ telegram-bot-api/Client.h | 4 ++-- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/td b/td index efc6bd5..38d31da 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit efc6bd553b61dea0ae8c0436695e8d2539bf03f9 +Subproject commit 38d31da77a72619cf7ec5d479338a48274cc7446 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 01b1b46..12105fb 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -742,25 +742,26 @@ class Client::JsonBirthdate final : public td::Jsonable { const td_api::birthdate *birthdate_; }; -class Client::JsonBusinessIntro final : public td::Jsonable { +class Client::JsonBusinessStartPage final : public td::Jsonable { public: - JsonBusinessIntro(const td_api::businessIntro *intro, const Client *client) : intro_(intro), client_(client) { + JsonBusinessStartPage(const td_api::businessStartPage *start_page, const Client *client) + : start_page_(start_page), client_(client) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - if (!intro_->title_.empty()) { - object("title", intro_->title_); + if (!start_page_->title_.empty()) { + object("title", start_page_->title_); } - if (!intro_->message_.empty()) { - object("message", intro_->message_); + if (!start_page_->message_.empty()) { + object("message", start_page_->message_); } - if (intro_->sticker_ != nullptr) { - object("sticker", JsonSticker(intro_->sticker_.get(), client_)); + if (start_page_->sticker_ != nullptr) { + object("sticker", JsonSticker(start_page_->sticker_.get(), client_)); } } private: - const td_api::businessIntro *intro_; + const td_api::businessStartPage *start_page_; const Client *client_; }; @@ -956,8 +957,8 @@ class Client::JsonChat final : public td::Jsonable { } if (user_info->business_info != nullptr) { auto business_info = user_info->business_info.get(); - if (business_info->intro_ != nullptr) { - object("business_intro", JsonBusinessIntro(business_info->intro_.get(), client_)); + if (business_info->start_page_ != nullptr) { + object("business_intro", JsonBusinessStartPage(business_info->start_page_.get(), client_)); } if (business_info->location_ != nullptr) { object("business_location", JsonBusinessLocation(business_info->location_.get())); @@ -4752,10 +4753,10 @@ class Client::TdOnGetChatCustomEmojiStickerSetCallback final : public TdQueryCal PromisedQueryPtr query_; }; -class Client::TdOnGetChatBusinessIntroStickerSetCallback final : public TdQueryCallback { +class Client::TdOnGetChatBusinessStartPageStickerSetCallback final : public TdQueryCallback { public: - TdOnGetChatBusinessIntroStickerSetCallback(Client *client, int64 chat_id, int64 pinned_message_id, - PromisedQueryPtr query) + TdOnGetChatBusinessStartPageStickerSetCallback(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)) { } @@ -4765,9 +4766,9 @@ class Client::TdOnGetChatBusinessIntroStickerSetCallback final : public TdQueryC CHECK(chat_info->type == ChatInfo::Type::Private); auto user_info = client_->add_user_info(chat_info->user_id); if (result->get_id() == td_api::error::ID) { - if (user_info->business_info != nullptr && user_info->business_info->intro_ != nullptr && - user_info->business_info->intro_->sticker_ != nullptr) { - user_info->business_info->intro_->sticker_->set_id_ = 0; + if (user_info->business_info != nullptr && user_info->business_info->start_page_ != nullptr && + user_info->business_info->start_page_->sticker_ != nullptr) { + user_info->business_info->start_page_->sticker_->set_id_ = 0; } } else { CHECK(result->get_id() == td_api::stickerSet::ID); @@ -4867,13 +4868,13 @@ class Client::TdOnGetChatPinnedMessageCallback final : public TdQueryCallback { auto user_info = client_->get_user_info(chat_info->user_id); CHECK(user_info != nullptr); - if (user_info->business_info != nullptr && user_info->business_info->intro_ != nullptr) { - auto *sticker = user_info->business_info->intro_->sticker_.get(); + if (user_info->business_info != nullptr && user_info->business_info->start_page_ != nullptr) { + auto *sticker = user_info->business_info->start_page_->sticker_.get(); if (sticker != nullptr) { auto sticker_set_id = 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( + td::make_unique( client_, chat_id_, pinned_message_id, std::move(query_))); } } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index f53b8e1..dd460b0 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -94,7 +94,7 @@ class Client final : public WebhookActor::Callback { class JsonReactionType; class JsonReactionCount; class JsonBirthdate; - class JsonBusinessIntro; + class JsonBusinessStartPage; class JsonBusinessLocation; class JsonBusinessOpeningHoursInterval; class JsonBusinessOpeningHours; @@ -226,7 +226,7 @@ class Client final : public WebhookActor::Callback { class TdOnGetChatFullInfoCallback; class TdOnGetChatStickerSetCallback; class TdOnGetChatCustomEmojiStickerSetCallback; - class TdOnGetChatBusinessIntroStickerSetCallback; + class TdOnGetChatBusinessStartPageStickerSetCallback; class TdOnGetChatPinnedMessageCallback; class TdOnGetChatPinnedMessageToUnpinCallback; class TdOnGetGroupMembersCallback; From d2ec2fff0018a5a7eaba800694dadb95abe182ce Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 1 May 2024 20:22:31 +0300 Subject: [PATCH 089/162] Add Message.chat_background_set. --- telegram-bot-api/Client.cpp | 129 +++++++++++++++++++++++++++++++++++- telegram-bot-api/Client.h | 3 + 2 files changed, 129 insertions(+), 3 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 12105fb..4f12f8e 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1738,6 +1738,128 @@ class Client::JsonStory final : public td::Jsonable { const Client *client_; }; +class Client::JsonBackgroundFill final : public td::Jsonable { + public: + explicit JsonBackgroundFill(const td_api::BackgroundFill *background_fill) : background_fill_(background_fill) { + } + void store(td::JsonValueScope *scope) const { + CHECK(background_fill_ != nullptr); + auto object = scope->enter_object(); + switch (background_fill_->get_id()) { + case td_api::backgroundFillSolid::ID: { + auto fill = static_cast(background_fill_); + object("type", "solid"); + object("color", fill->color_); + break; + } + case td_api::backgroundFillGradient::ID: { + auto fill = static_cast(background_fill_); + object("type", "gradient"); + object("top_color", fill->top_color_); + object("bottom_color", fill->bottom_color_); + object("rotation_angle", fill->rotation_angle_); + break; + } + case td_api::backgroundFillFreeformGradient::ID: { + auto fill = static_cast(background_fill_); + object("type", "freeform_gradient"); + object("colors", td::json_array(fill->colors_, [](int32 color) { return color; })); + break; + } + default: + UNREACHABLE(); + } + } + + private: + const td_api::BackgroundFill *background_fill_; +}; + +class Client::JsonBackgroundType final : public td::Jsonable { + public: + JsonBackgroundType(const td_api::BackgroundType *background_type, const td_api::document *document, + int32 dark_theme_dimming, const Client *client) + : background_type_(background_type) + , document_(document) + , dark_theme_dimming_(dark_theme_dimming) + , client_(client) { + } + void store(td::JsonValueScope *scope) const { + CHECK(background_type_ != nullptr); + auto object = scope->enter_object(); + switch (background_type_->get_id()) { + case td_api::backgroundTypeWallpaper::ID: { + auto type = static_cast(background_type_); + object("type", "wallpaper"); + CHECK(document_ != nullptr); + object("document", JsonDocument(document_, client_)); + object("dark_theme_dimming", dark_theme_dimming_); + if (type->is_blurred_) { + object("is_blurred", td::JsonTrue()); + } + if (type->is_moving_) { + object("is_moving", td::JsonTrue()); + } + break; + } + case td_api::backgroundTypePattern::ID: { + auto type = static_cast(background_type_); + object("type", "pattern"); + CHECK(document_ != nullptr); + object("document", JsonDocument(document_, client_)); + object("fill", JsonBackgroundFill(type->fill_.get())); + object("intensity", type->intensity_); + if (type->is_inverted_) { + object("is_inverted", td::JsonTrue()); + } + if (type->is_moving_) { + object("is_moving", td::JsonTrue()); + } + break; + } + case td_api::backgroundTypeFill::ID: { + auto type = static_cast(background_type_); + object("type", "fill"); + object("fill", JsonBackgroundFill(type->fill_.get())); + object("dark_theme_dimming", dark_theme_dimming_); + break; + } + case td_api::backgroundTypeChatTheme::ID: { + auto type = static_cast(background_type_); + object("type", "chat_theme"); + object("theme_name", type->theme_name_); + break; + } + default: + UNREACHABLE(); + } + } + + private: + const td_api::BackgroundType *background_type_; + const td_api::document *document_; + int32 dark_theme_dimming_; + const Client *client_; +}; + +class Client::JsonChatBackground final : public td::Jsonable { + public: + JsonChatBackground(const td_api::chatBackground *chat_background, const Client *client) + : chat_background_(chat_background), client_(client) { + } + void store(td::JsonValueScope *scope) const { + CHECK(chat_background_ != nullptr); + auto object = scope->enter_object(); + auto background = chat_background_->background_.get(); + object("type", JsonBackgroundType(background->type_.get(), background->document_.get(), + chat_background_->dark_theme_dimming_, client_)); + } + + private: + const td_api::chatBackground *chat_background_; + const Client *client_; +}; + class Client::JsonForumTopicCreated final : public td::Jsonable { public: explicit JsonForumTopicCreated(const td_api::messageForumTopicCreated *forum_topic_created) @@ -3005,8 +3127,11 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("story", JsonStory(content->story_sender_chat_id_, content->story_id_, client_)); break; } - case td_api::messageChatSetBackground::ID: + case td_api::messageChatSetBackground::ID: { + auto content = static_cast(message_->content.get()); + object("chat_background_set", JsonChatBackground(content->background_.get(), client_)); break; + } case td_api::messagePremiumGiftCode::ID: break; case td_api::messagePremiumGiveawayCreated::ID: @@ -12995,8 +13120,6 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr Date: Thu, 2 May 2024 17:10:28 +0300 Subject: [PATCH 090/162] Reget inaccessible users. --- telegram-bot-api/Client.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 4f12f8e..1492853 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -5837,7 +5837,7 @@ void Client::check_user_read_access(const UserInfo *user_info, PromisedQueryPtr template void Client::check_user(int64 user_id, PromisedQueryPtr query, OnSuccess on_success) { const UserInfo *user_info = get_user_info(user_id); - if (user_info != nullptr) { + if (user_info != nullptr && user_info->have_access) { return check_user_read_access(user_info, std::move(query), std::move(on_success)); } send_request(make_object(user_id), @@ -5847,7 +5847,7 @@ void Client::check_user(int64 user_id, PromisedQueryPtr query, OnSuccess on_succ template void Client::check_user_no_fail(int64 user_id, PromisedQueryPtr query, OnSuccess on_success) { const UserInfo *user_info = get_user_info(user_id); - if (user_info != nullptr) { + if (user_info != nullptr && user_info->have_access) { on_success(std::move(query)); return; } @@ -5943,6 +5943,12 @@ void Client::check_chat(td::Slice chat_id_str, AccessRights access_rights, Promi auto chat_id = td::to_integer(chat_id_str); auto chat_info = get_chat(chat_id); + if (chat_info != nullptr && chat_info->type == ChatInfo::Type::Private) { + const UserInfo *user_info = get_user_info(chat_info->user_id); + if (user_info == nullptr || !user_info->have_access) { + chat_info = nullptr; + } + } if (chat_info != nullptr) { return check_chat_access(chat_id, access_rights, chat_info, std::move(query), std::move(on_success)); } @@ -5964,6 +5970,12 @@ void Client::check_chat_no_fail(td::Slice chat_id_str, PromisedQueryPtr query, O auto chat_id = r_chat_id.move_as_ok(); auto chat_info = get_chat(chat_id); + if (chat_info != nullptr && chat_info->type == ChatInfo::Type::Private) { + const UserInfo *user_info = get_user_info(chat_info->user_id); + if (user_info == nullptr || !user_info->have_access) { + chat_info = nullptr; + } + } if (chat_info != nullptr) { return on_success(chat_id, std::move(query)); } From a5a1c509ebc568e7811961dd7fb5c9304d7f56bd Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 4 May 2024 00:21:18 +0300 Subject: [PATCH 091/162] Update TDLib to 1.8.29. --- td | 2 +- telegram-bot-api/Client.cpp | 48 ++++++++++++++----------------- telegram-bot-api/Client.h | 2 +- telegram-bot-api/WebhookActor.cpp | 3 +- 4 files changed, 24 insertions(+), 31 deletions(-) diff --git a/td b/td index 38d31da..af69dd4 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 38d31da77a72619cf7ec5d479338a48274cc7446 +Subproject commit af69dd4397b6dc1bf23ba0fd0bf429fcba6454f6 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 1492853..5b5a065 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1634,7 +1634,7 @@ class Client::JsonPollOption final : public td::Jsonable { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("text", option_->text_); + object("text", option_->text_->text_); object("voter_count", option_->voter_count_); // ignore is_chosen } @@ -1650,7 +1650,7 @@ class Client::JsonPoll final : public td::Jsonable { void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); object("id", td::to_string(poll_->id_)); - object("question", poll_->question_); + object("question", poll_->question_->text_); object("options", td::json_array(poll_->options_, [](auto &option) { return JsonPollOption(option.get()); })); object("total_voter_count", poll_->total_voter_count_); if (poll_->open_period_ != 0 && poll_->close_date_ != 0) { @@ -2395,7 +2395,7 @@ class Client::JsonGiveawayCompleted final : public td::Jsonable { class Client::JsonChatBoostAdded final : public td::Jsonable { public: - JsonChatBoostAdded(const td_api::messageChatBoost *chat_boost) : chat_boost_(chat_boost) { + explicit JsonChatBoostAdded(const td_api::messageChatBoost *chat_boost) : chat_boost_(chat_boost) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); @@ -3895,8 +3895,7 @@ class Client::JsonBusinessMessagesDeleted final : public td::Jsonable { auto object = scope->enter_object(); object("business_connection_id", update_->connection_id_); object("chat", JsonChat(update_->chat_id_, client_)); - object("message_ids", - td::json_array(update_->message_ids_, [](int64 message_id) { return as_client_message_id(message_id); })); + object("message_ids", td::json_array(update_->message_ids_, as_client_message_id)); } private: @@ -6142,7 +6141,7 @@ void Client::check_reply_parameters(td::Slice chat_id_str, InputReplyParameters } if (message_thread_id <= 0) { - // if message thread isn't specified, then the message to reply can be only from a different chat + // if message thread isn't specified, then the message to be replied can be only from a different chat if (reply_parameters.reply_in_chat_id == chat_id) { reply_parameters.reply_in_chat_id = 0; } @@ -6172,13 +6171,13 @@ void Client::check_reply_parameters(td::Slice chat_id_str, InputReplyParameters 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"); + return fail_query_with_error(std::move(query), 400, "MESSAGE_NOT_FOUND", "message to be replied 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))); + this, reply_in_chat_id, reply_to_message_id, allow_sending_without_reply, + "message to be replied", 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)); @@ -9249,7 +9248,7 @@ td::Result> Client::get_input_me provider_token.str(), provider_data.str(), start_parameter.str(), std::move(extended_media)); } -td::Result> Client::get_poll_options(const Query *query) { +td::Result>> Client::get_poll_options(const Query *query) { auto input_options = query->arg("options"); LOG(INFO) << "Parsing JSON object: " << input_options; auto r_value = json_decode(input_options); @@ -9263,12 +9262,12 @@ td::Result> Client::get_poll_options(const Query *query) return td::Status::Error(400, "Expected an Array of String as options"); } - td::vector options; + td::vector> options; for (auto &input_option : value.get_array()) { if (input_option.type() != td::JsonValue::Type::String) { return td::Status::Error(400, "Expected an option to be of type String"); } - options.push_back(input_option.get_string().str()); + options.push_back(make_object(input_option.get_string().str(), td::Auto())); } return std::move(options); } @@ -9953,8 +9952,9 @@ td::Status Client::process_send_poll_query(PromisedQueryPtr &query) { int32 open_period = get_integer_arg(query.get(), "open_period", 0, 0, 10 * 60); int32 close_date = get_integer_arg(query.get(), "close_date", 0); auto is_closed = to_bool(query->arg("is_closed")); - do_send_message(make_object(question.str(), std::move(options), is_anonymous, - std::move(poll_type), open_period, close_date, is_closed), + do_send_message(make_object(make_object(question.str(), td::Auto()), + std::move(options), is_anonymous, std::move(poll_type), + open_period, close_date, is_closed), std::move(query)); return td::Status::OK(); } @@ -10254,8 +10254,8 @@ td::Status Client::process_edit_message_live_location_query(PromisedQueryPtr &qu [this, inline_message_id = inline_message_id.str(), location = std::move(location), heading, proximity_alert_radius](object_ptr reply_markup, PromisedQueryPtr query) mutable { send_request( - make_object(inline_message_id, std::move(reply_markup), - std::move(location), heading, proximity_alert_radius), + make_object( + inline_message_id, std::move(reply_markup), std::move(location), 0, heading, proximity_alert_radius), td::make_unique(std::move(query))); }); } else { @@ -10268,8 +10268,8 @@ td::Status Client::process_edit_message_live_location_query(PromisedQueryPtr &qu reply_markup = std::move(reply_markup)](int64 chat_id, int64 message_id, PromisedQueryPtr query) mutable { send_request(make_object( - chat_id, message_id, std::move(reply_markup), std::move(location), heading, - proximity_alert_radius), + chat_id, message_id, std::move(reply_markup), std::move(location), 0, + heading, proximity_alert_radius), td::make_unique(this, std::move(query))); }); }); @@ -10956,7 +10956,7 @@ td::Status Client::process_get_chat_member_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); TRY_RESULT(user_id, get_user_id(query.get())); - check_chat(chat_id, AccessRights::ReadMembers, std::move(query), + check_chat(chat_id, user_id == my_id_ ? AccessRights::Read : AccessRights::ReadMembers, std::move(query), [this, user_id](int64 chat_id, PromisedQueryPtr query) { get_chat_member(chat_id, user_id, std::move(query), [this, chat_type = get_chat_type(chat_id)](object_ptr &&chat_member, @@ -12950,14 +12950,8 @@ void Client::add_update_message_reaction_count(object_ptr &&update) { CHECK(update != nullptr); const auto *connection = add_business_connection(std::move(update->connection_), true); - auto left_time = connection->date_ + 86400 - get_unix_time(); - if (left_time > 0) { - auto webhook_queue_id = connection->user_id_ + (static_cast(10) << 33); - add_update(UpdateType::BusinessConnection, JsonBusinessConnection(connection, this), left_time, webhook_queue_id); - } else { - LOG(DEBUG) << "Skip updateBusinessConnection with date " << connection->date_ << ", because current date is " - << get_unix_time(); - } + auto webhook_queue_id = connection->user_id_ + (static_cast(10) << 33); + add_update(UpdateType::BusinessConnection, JsonBusinessConnection(connection, this), 86400, webhook_queue_id); } void Client::add_update_business_messages_deleted(object_ptr &&update) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 86e10ae..9b140bc 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -563,7 +563,7 @@ class Client final : public WebhookActor::Callback { static object_ptr get_message_send_options(bool disable_notification, bool protect_content); - static td::Result> get_poll_options(const Query *query); + static td::Result>> get_poll_options(const Query *query); static td::Result> get_reaction_type(td::JsonValue &&value); diff --git a/telegram-bot-api/WebhookActor.cpp b/telegram-bot-api/WebhookActor.cpp index 7e04a67..3e0caa0 100644 --- a/telegram-bot-api/WebhookActor.cpp +++ b/telegram-bot-api/WebhookActor.cpp @@ -590,8 +590,7 @@ void WebhookActor::send_updates() { void WebhookActor::handle(td::unique_ptr response) { SCOPE_EXIT { - bool dummy = false; - td::Scheduler::instance()->destroy_on_scheduler(SharedData::get_file_gc_scheduler_id(), response, dummy); + td::Scheduler::instance()->destroy_on_scheduler_unique_ptr(SharedData::get_file_gc_scheduler_id(), response); }; auto connection_id = get_link_token(); From 9f4e8eb86758eb97954470c22a269e2273bc500d Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 4 May 2024 00:31:50 +0300 Subject: [PATCH 092/162] Add Chat.max_reaction_count. --- telegram-bot-api/Client.cpp | 31 ++++++++++++++++++++++--------- telegram-bot-api/Client.h | 4 ++++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 5b5a065..7778364 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1142,6 +1142,7 @@ class Client::JsonChat final : public td::Jsonable { td::json_array(chat_info->available_reactions->reactions_, [](const auto &reaction) { return JsonReactionType(reaction.get()); })); } + object("max_reaction_count", chat_info->max_reaction_count); CHECK(chat_info->accent_color_id != -1); object("accent_color_id", chat_info->accent_color_id); if (chat_info->background_custom_emoji_id != 0) { @@ -6591,9 +6592,7 @@ void Client::on_update(object_ptr result) { 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_); - } + set_chat_available_reactions(chat_info, std::move(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->profile_accent_color_id = chat->profile_accent_color_id_; @@ -6643,12 +6642,7 @@ void Client::on_update(object_ptr result) { 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; - } + set_chat_available_reactions(chat_info, std::move(update->available_reactions_)); break; } case td_api::updateChatAccentColors::ID: { @@ -12349,6 +12343,25 @@ const Client::ChatInfo *Client::get_chat(int64 chat_id) const { return chats_.get_pointer(chat_id); } +void Client::set_chat_available_reactions(ChatInfo *chat_info, + object_ptr &&available_reactions) { + CHECK(chat_info != nullptr); + CHECK(available_reactions != nullptr); + switch (available_reactions->get_id()) { + case td_api::chatAvailableReactionsSome::ID: + chat_info->available_reactions = move_object_as(available_reactions); + chat_info->max_reaction_count = chat_info->available_reactions->max_reaction_count_; + break; + case td_api::chatAvailableReactionsAll::ID: + chat_info->available_reactions = nullptr; + chat_info->max_reaction_count = + static_cast(available_reactions.get())->max_reaction_count_; + break; + default: + UNREACHABLE(); + } +} + Client::ChatType Client::get_chat_type(int64 chat_id) const { auto chat_info = get_chat(chat_id); if (chat_info == nullptr) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 9b140bc..679e077 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -878,6 +878,7 @@ class Client final : public WebhookActor::Callback { int64 background_custom_emoji_id = 0; int64 profile_background_custom_emoji_id = 0; bool has_protected_content = false; + int32 max_reaction_count = 0; object_ptr available_reactions; object_ptr photo_info; object_ptr permissions; @@ -890,6 +891,9 @@ class Client final : public WebhookActor::Callback { ChatInfo *add_chat(int64 chat_id); const ChatInfo *get_chat(int64 chat_id) const; + void set_chat_available_reactions(ChatInfo *chat_info, + object_ptr &&available_reactions); + enum class ChatType { Private, Group, Supergroup, Channel, Unknown }; ChatType get_chat_type(int64 chat_id) const; From 7febd857d6d6084e291f80667ccbd0373959f637 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 4 May 2024 00:57:31 +0300 Subject: [PATCH 093/162] Add ChatMemberUpdated.via_join_request. --- 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 7778364..3502e19 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3655,6 +3655,9 @@ class Client::JsonChatMemberUpdated final : public td::Jsonable { if (update_->invite_link_ != nullptr) { object("invite_link", JsonChatInviteLink(update_->invite_link_.get(), client_)); } + if (update_->via_join_request_) { + object("via_join_request", td::JsonTrue()); + } if (update_->via_chat_folder_invite_link_) { object("via_chat_folder_invite_link", td::JsonTrue()); } From ff01a73df3794c31670ecaa08d2a30d049ec5c72 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 4 May 2024 01:12:16 +0300 Subject: [PATCH 094/162] Add live_period parameter to editMessageLiveLocation. --- telegram-bot-api/Client.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 3502e19..783c996 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -10235,6 +10235,7 @@ td::Status Client::process_edit_message_text_query(PromisedQueryPtr &query) { td::Status Client::process_edit_message_live_location_query(PromisedQueryPtr &query) { object_ptr location = nullptr; + int32 live_period = get_integer_arg(query.get(), "live_period", 0); int32 heading = get_integer_arg(query.get(), "heading", 0); int32 proximity_alert_radius = get_integer_arg(query.get(), "proximity_alert_radius", 0); if (query->method() == "editmessagelivelocation") { @@ -10248,25 +10249,25 @@ td::Status Client::process_edit_message_live_location_query(PromisedQueryPtr &qu TRY_RESULT(inline_message_id, get_inline_message_id(query.get())); resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, inline_message_id = inline_message_id.str(), location = std::move(location), heading, + [this, inline_message_id = inline_message_id.str(), location = std::move(location), live_period, heading, proximity_alert_radius](object_ptr reply_markup, PromisedQueryPtr query) mutable { - send_request( - make_object( - inline_message_id, std::move(reply_markup), std::move(location), 0, heading, proximity_alert_radius), - td::make_unique(std::move(query))); + send_request(make_object(inline_message_id, std::move(reply_markup), + std::move(location), live_period, heading, + proximity_alert_radius), + td::make_unique(std::move(query))); }); } else { resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, chat_id = chat_id.str(), message_id, location = std::move(location), heading, proximity_alert_radius]( - object_ptr reply_markup, PromisedQueryPtr query) mutable { + [this, chat_id = chat_id.str(), message_id, location = std::move(location), live_period, heading, + proximity_alert_radius](object_ptr reply_markup, PromisedQueryPtr query) mutable { check_message(chat_id, message_id, false, AccessRights::Edit, "message to edit", std::move(query), - [this, location = std::move(location), heading, proximity_alert_radius, + [this, location = std::move(location), live_period, heading, proximity_alert_radius, reply_markup = std::move(reply_markup)](int64 chat_id, int64 message_id, PromisedQueryPtr query) mutable { send_request(make_object( - chat_id, message_id, std::move(reply_markup), std::move(location), 0, - heading, proximity_alert_radius), + chat_id, message_id, std::move(reply_markup), std::move(location), + live_period, heading, proximity_alert_radius), td::make_unique(this, std::move(query))); }); }); From 1d3a1f2bf16128c88ca3fd0c17fabbfe05d42406 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 4 May 2024 01:49:17 +0300 Subject: [PATCH 095/162] Support custom emoji entities in incoming polls. --- telegram-bot-api/Client.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 783c996..881cbf2 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1631,17 +1631,21 @@ class Client::JsonInvoice final : public td::Jsonable { class Client::JsonPollOption final : public td::Jsonable { public: - explicit JsonPollOption(const td_api::pollOption *option) : option_(option) { + JsonPollOption(const td_api::pollOption *option, const Client *client) : option_(option), client_(client) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); object("text", option_->text_->text_); + if (!option_->text_->entities_.empty()) { + object("text_entities", JsonVectorEntities(option_->text_->entities_, client_)); + } object("voter_count", option_->voter_count_); // ignore is_chosen } private: const td_api::pollOption *option_; + const Client *client_; }; class Client::JsonPoll final : public td::Jsonable { @@ -1652,7 +1656,12 @@ class Client::JsonPoll final : public td::Jsonable { auto object = scope->enter_object(); object("id", td::to_string(poll_->id_)); object("question", poll_->question_->text_); - object("options", td::json_array(poll_->options_, [](auto &option) { return JsonPollOption(option.get()); })); + if (!poll_->question_->entities_.empty()) { + object("question_entities", JsonVectorEntities(poll_->question_->entities_, client_)); + } + object("options", td::json_array(poll_->options_, [client = client_](auto &option) { + return JsonPollOption(option.get(), client); + })); object("total_voter_count", poll_->total_voter_count_); if (poll_->open_period_ != 0 && poll_->close_date_ != 0) { object("open_period", poll_->open_period_); From 681e67c055ddee40c6d8e12f270bc1dc69825885 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 4 May 2024 01:56:10 +0300 Subject: [PATCH 096/162] Support sending polls with custom emoji. --- telegram-bot-api/Client.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 881cbf2..33c3943 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -9271,6 +9271,16 @@ td::Result>> Client::get_po td::vector> options; for (auto &input_option : value.get_array()) { if (input_option.type() != td::JsonValue::Type::String) { + if (input_option.type() == td::JsonValue::Type::Object) { + auto &object = input_option.get_object(); + TRY_RESULT(text, object.get_required_string_field("text")); + TRY_RESULT(parse_mode, object.get_optional_string_field("text_parse_mode")); + TRY_RESULT(option_text, + get_formatted_text(std::move(text), std::move(parse_mode), object.extract_field("text_entities"))); + options.push_back(std::move(option_text)); + continue; + } + return td::Status::Error(400, "Expected an option to be of type String"); } options.push_back(make_object(input_option.get_string().str(), td::Auto())); @@ -9934,7 +9944,8 @@ td::Status Client::process_send_contact_query(PromisedQueryPtr &query) { } td::Status Client::process_send_poll_query(PromisedQueryPtr &query) { - auto question = query->arg("question"); + TRY_RESULT(question, get_formatted_text(query->arg("question").str(), query->arg("question_parse_mode").str(), + get_input_entities(query.get(), "question_entities"))); TRY_RESULT(options, get_poll_options(query.get())); bool is_anonymous = true; if (query->has_arg("is_anonymous")) { @@ -9958,9 +9969,8 @@ td::Status Client::process_send_poll_query(PromisedQueryPtr &query) { int32 open_period = get_integer_arg(query.get(), "open_period", 0, 0, 10 * 60); int32 close_date = get_integer_arg(query.get(), "close_date", 0); auto is_closed = to_bool(query->arg("is_closed")); - do_send_message(make_object(make_object(question.str(), td::Auto()), - std::move(options), is_anonymous, std::move(poll_type), - open_period, close_date, is_closed), + do_send_message(make_object(std::move(question), std::move(options), is_anonymous, + std::move(poll_type), open_period, close_date, is_closed), std::move(query)); return td::Status::OK(); } From f95d406da67adb8ac13d9c562291aa57c65398e0 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 4 May 2024 02:37:29 +0300 Subject: [PATCH 097/162] Update version to 7.3. --- 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 1028fe4..276606d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 7.2 LANGUAGES CXX) +project(TelegramBotApi VERSION 7.3 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 97b8fe7..f66a522 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.2"; + parameters->version_ = "7.3"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats(); From 5951bfbab8b1274437c613c1c48d91be2a050371 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 14 May 2024 17:28:42 +0300 Subject: [PATCH 098/162] Port build instructions generator changes. --- build.html | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/build.html b/build.html index 38bf606..e1d7c7a 100644 --- a/build.html +++ b/build.html @@ -208,6 +208,7 @@ +

@@ -260,7 +261,7 @@
- +

@@ -446,7 +447,7 @@ function onOptionsChanged() { pre_text.push('Install Git, ' + compiler + ', make, CMake >= 3.0.2, OpenSSL-dev, zlib-dev, gperf using your package manager.'); } if (os_freebsd) { - pre_text.push('Note that the following instruction is for FreeBSD 11.'); + pre_text.push('Note that the following instruction is for FreeBSD 13.'); pre_text.push('Note that the following calls to pkg needs to be run as root.'); } if (os_openbsd) { @@ -496,6 +497,19 @@ function onOptionsChanged() { return '-10'; case 'Ubuntu 22': return '-14'; + case 'Ubuntu 24': + return '-18'; + default: + return ''; // use default version + } + } + + function getLibcplusplusVersionSuffix() { + switch (linux_distro) { + case 'Ubuntu 20': + case 'Ubuntu 22': + case 'Ubuntu 24': + return getClangVersionSuffix(); default: return ''; // use default version } @@ -514,7 +528,7 @@ function onOptionsChanged() { commands.push(sudo + 'apk update'); commands.push(sudo + 'apk upgrade'); var packages = 'alpine-sdk linux-headers git zlib-dev openssl-dev gperf cmake'; - commands.push(sudo + 'apk add --update ' + packages); + commands.push(sudo + 'apk add ' + packages); break; case 'CentOS 7': case 'CentOS 8': @@ -538,6 +552,7 @@ function onOptionsChanged() { case 'Ubuntu 18': case 'Ubuntu 20': case 'Ubuntu 22': + case 'Ubuntu 24': if (linux_distro.includes('Debian') && !use_root) { commands.push('su -'); } @@ -553,9 +568,9 @@ function onOptionsChanged() { packages += ' cmake'; } if (use_clang) { - packages += ' clang' + getClangVersionSuffix() + ' libc++-dev'; - if (linux_distro === 'Debian 10+' || linux_distro === 'Ubuntu 18' || linux_distro === 'Ubuntu 20' || linux_distro === 'Ubuntu 22') { - packages += ' libc++abi-dev'; + packages += ' clang' + getClangVersionSuffix() + ' libc++' + getLibcplusplusVersionSuffix() + '-dev'; + if (linux_distro === 'Debian 10+' || linux_distro === 'Ubuntu 18' || linux_distro === 'Ubuntu 20' || linux_distro === 'Ubuntu 22' || linux_distro === 'Ubuntu 24') { + packages += ' libc++abi' + getLibcplusplusVersionSuffix() + '-dev'; } } else { packages += ' g++'; @@ -587,7 +602,7 @@ function onOptionsChanged() { commands.push('su -'); } commands.push('export PKG_PATH=http://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/$(uname -p)/$(uname -r)/All'); - var packages = 'git gperf cmake openssl gcc12-libs mozilla-rootcerts-openssl'; + var packages = 'git gperf pcre2 cmake openssl gcc12-libs mozilla-rootcerts-openssl'; commands.push('pkg_add ' + packages); if (!use_root) { commands.push('exit'); From 14ea0576cd1c04c20f1b5f575eea56d9ddc96651 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 20 May 2024 14:13:18 +0300 Subject: [PATCH 099/162] Update TDLib to 1.8.30. --- td | 2 +- telegram-bot-api/Client.cpp | 44 +++++++++++++++++++------------------ 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/td b/td index af69dd4..fab354a 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit af69dd4397b6dc1bf23ba0fd0bf429fcba6454f6 +Subproject commit fab354add5a257a8121a4a7f1ff6b1b9fa9a9073 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 33c3943..fe04e63 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -542,7 +542,8 @@ class Client::JsonVectorEntities final : public td::Jsonable { auto array = scope->enter_array(); for (auto &entity : entities_) { auto entity_type = entity->type_->get_id(); - if (entity_type != td_api::textEntityTypeBankCardNumber::ID && + if (entity_type != td_api::textEntityTypeExpandableBlockQuote::ID && + entity_type != td_api::textEntityTypeBankCardNumber::ID && entity_type != td_api::textEntityTypeMediaTimestamp::ID) { array << JsonEntity(entity.get(), client_); } @@ -1614,12 +1615,12 @@ class Client::JsonInvoice final : public td::Jsonable { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("title", invoice_->title_); - object("description", invoice_->description_->text_); + object("title", invoice_->product_info_->title_); + object("description", invoice_->product_info_->description_->text_); object("start_parameter", invoice_->start_parameter_); object("currency", invoice_->currency_); object("total_amount", invoice_->total_amount_); - // skip photo + // skip product_info_->photo // skip is_test // skip need_shipping_address // skip receipt_message_id @@ -7717,7 +7718,7 @@ td::Result> Client::get_input_me td_api::object_ptr Client::get_message_send_options(bool disable_notification, bool protect_content) { - return make_object(disable_notification, false, protect_content, false, nullptr, 0, + return make_object(disable_notification, false, protect_content, false, nullptr, 0, 0, false); } @@ -7971,7 +7972,7 @@ td::Result> Client::get_inlin if (input_message_content == nullptr) { input_message_content = make_object( - nullptr, nullptr, td::vector(), gif_duration, gif_width, gif_height, std::move(caption), false); + nullptr, nullptr, td::vector(), gif_duration, gif_width, gif_height, std::move(caption), false, false); } return make_object( id, title, thumbnail_url, thumbnail_mime_type, gif_url, "image/gif", gif_duration, gif_width, gif_height, @@ -8011,8 +8012,9 @@ td::Result> Client::get_inlin } if (input_message_content == nullptr) { - input_message_content = make_object( - nullptr, nullptr, td::vector(), mpeg4_duration, mpeg4_width, mpeg4_height, std::move(caption), false); + input_message_content = + make_object(nullptr, nullptr, td::vector(), mpeg4_duration, mpeg4_width, + mpeg4_height, std::move(caption), false, false); } return make_object( id, title, thumbnail_url, thumbnail_mime_type, mpeg4_url, "video/mp4", mpeg4_duration, mpeg4_width, @@ -8030,7 +8032,7 @@ td::Result> Client::get_inlin if (input_message_content == nullptr) { input_message_content = make_object(nullptr, nullptr, td::vector(), 0, 0, - std::move(caption), nullptr, false); + std::move(caption), false, nullptr, false); } return make_object(id, title, description, thumbnail_url, photo_url, photo_width, photo_height, std::move(reply_markup), @@ -8097,7 +8099,7 @@ td::Result> Client::get_inlin if (input_message_content == nullptr) { input_message_content = make_object(nullptr, nullptr, td::vector(), video_duration, video_width, - video_height, false, std::move(caption), nullptr, false); + video_height, false, std::move(caption), false, nullptr, false); } return make_object(id, title, description, thumbnail_url, video_url, mime_type, video_width, video_height, video_duration, @@ -9087,7 +9089,7 @@ td::Result> Client::get_input_me TRY_RESULT(type, object.get_required_string_field("type")); if (type == "photo") { return make_object(std::move(input_file), nullptr, td::vector(), 0, 0, - std::move(caption), nullptr, has_spoiler); + std::move(caption), false, nullptr, has_spoiler); } if (type == "video") { TRY_RESULT(width, object.get_optional_int_field("width")); @@ -9100,7 +9102,7 @@ td::Result> Client::get_input_me return make_object(std::move(input_file), std::move(input_thumbnail), td::vector(), duration, width, height, supports_streaming, - std::move(caption), nullptr, has_spoiler); + std::move(caption), false, nullptr, has_spoiler); } if (for_album && type == "animation") { return td::Status::Error(PSLICE() << "type \"" << type << "\" can't be used in sendMediaGroup"); @@ -9114,7 +9116,7 @@ td::Result> Client::get_input_me duration = td::clamp(duration, 0, MAX_DURATION); return make_object(std::move(input_file), std::move(input_thumbnail), td::vector(), duration, width, height, std::move(caption), - has_spoiler); + false, has_spoiler); } if (type == "audio") { TRY_RESULT(duration, object.get_optional_int_field("duration")); @@ -9767,7 +9769,7 @@ td::Status Client::process_send_animation_query(PromisedQueryPtr &query) { auto has_spoiler = to_bool(query->arg("has_spoiler")); do_send_message( make_object(std::move(animation), std::move(thumbnail), td::vector(), - duration, width, height, std::move(caption), has_spoiler), + duration, width, height, std::move(caption), false, has_spoiler), std::move(query)); return td::Status::OK(); } @@ -9816,7 +9818,7 @@ td::Status Client::process_send_photo_query(PromisedQueryPtr &query) { TRY_RESULT(caption, get_caption(query.get())); auto has_spoiler = to_bool(query->arg("has_spoiler")); do_send_message(make_object(std::move(photo), nullptr, td::vector(), 0, 0, - std::move(caption), nullptr, has_spoiler), + std::move(caption), false, nullptr, has_spoiler), std::move(query)); return td::Status::OK(); } @@ -9846,7 +9848,7 @@ td::Status Client::process_send_video_query(PromisedQueryPtr &query) { auto has_spoiler = to_bool(query->arg("has_spoiler")); do_send_message(make_object(std::move(video), std::move(thumbnail), td::vector(), duration, width, height, supports_streaming, - std::move(caption), nullptr, has_spoiler), + std::move(caption), false, nullptr, has_spoiler), std::move(query)); return td::Status::OK(); } @@ -10003,7 +10005,7 @@ td::Status Client::process_copy_message_query(PromisedQueryPtr &query) { if (replace_caption) { TRY_RESULT_ASSIGN(caption, get_caption(query.get())); } - auto options = make_object(true, replace_caption, std::move(caption)); + auto options = make_object(true, replace_caption, std::move(caption), false); check_message( from_chat_id, message_id, false, AccessRights::Read, "message to copy", std::move(query), @@ -10143,7 +10145,7 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { send_request( make_object( business_connection->id_, chat_id, get_input_message_reply_to(std::move(reply_parameters)), - disable_notification, protect_content, std::move(input_message_contents)), + disable_notification, protect_content, 0, std::move(input_message_contents)), td::make_unique(this, business_connection->id_, std::move(query))); }); @@ -10341,7 +10343,7 @@ td::Status Client::process_edit_message_caption_query(PromisedQueryPtr &query) { [this, inline_message_id = inline_message_id.str(), caption = std::move(caption)]( object_ptr reply_markup, PromisedQueryPtr query) mutable { send_request(make_object(inline_message_id, std::move(reply_markup), - std::move(caption)), + std::move(caption), false), td::make_unique(std::move(query))); }); } else { @@ -10353,7 +10355,7 @@ td::Status Client::process_edit_message_caption_query(PromisedQueryPtr &query) { [this, reply_markup = std::move(reply_markup), caption = std::move(caption)]( int64 chat_id, int64 message_id, PromisedQueryPtr query) mutable { send_request(make_object( - chat_id, message_id, std::move(reply_markup), std::move(caption)), + chat_id, message_id, std::move(reply_markup), std::move(caption), false), td::make_unique(this, std::move(query))); }); }); @@ -11989,7 +11991,7 @@ void Client::do_send_message(object_ptr input_messa send_request( make_object(business_connection->id_, chat_id, get_input_message_reply_to(std::move(reply_parameters)), - disable_notification, protect_content, + disable_notification, protect_content, 0, std::move(reply_markup), std::move(input_message_content)), td::make_unique(this, business_connection->id_, std::move(query))); }); From 278e1e254afee3fe9e44531d4795d2b2f5fe4fe1 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 20 May 2024 14:20:55 +0300 Subject: [PATCH 100/162] Add Message.effect_id. --- 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 fe04e63..5606809 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3186,6 +3186,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { if (message_->is_from_offline) { object("is_from_offline", td::JsonTrue()); } + if (message_->effect_id != 0) { + object("effect_id", td::to_string(message_->effect_id)); + } } class Client::JsonMessageId final : public td::Jsonable { @@ -13676,6 +13679,7 @@ void Client::init_message(MessageInfo *message_info, object_ptr 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_; + message_info->effect_id = message->effect_id_; drop_internal_reply_to_message_in_another_chat(message); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 679e077..f37d537 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -921,6 +921,7 @@ class Client final : public WebhookActor::Callback { object_ptr reply_markup; td::string business_connection_id; int64 sender_business_bot_user_id = 0; + int64 effect_id = 0; bool can_be_saved = false; bool is_automatic_forward = false; From 7eee0eed846e5fda0072c916481328bf0f95a404 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 20 May 2024 14:27:04 +0300 Subject: [PATCH 101/162] Add message.show_caption_above_media. --- telegram-bot-api/Client.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 5606809..025f847 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -901,7 +901,8 @@ class Client::JsonMessage final : public td::Jsonable { const td::string &source_; const Client *client_; - void add_caption(td::JsonObjectScope &object, const object_ptr &caption) const { + void add_caption(td::JsonObjectScope &object, const object_ptr &caption, + bool show_caption_above_media) const { CHECK(caption != nullptr); if (!caption->text_.empty()) { object("caption", caption->text_); @@ -909,6 +910,10 @@ class Client::JsonMessage final : public td::Jsonable { if (!caption->entities_.empty()) { object("caption_entities", JsonVectorEntities(caption->entities_, client_)); } + + if (show_caption_above_media) { + object("show_caption_above_media", td::JsonTrue()); + } } } @@ -2814,27 +2819,27 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { auto content = static_cast(message_->content.get()); object("animation", JsonAnimation(content->animation_.get(), false, client_)); object("document", JsonAnimation(content->animation_.get(), true, client_)); - add_caption(object, content->caption_); + add_caption(object, content->caption_, content->show_caption_above_media_); add_media_spoiler(object, content->has_spoiler_); break; } case td_api::messageAudio::ID: { auto content = static_cast(message_->content.get()); object("audio", JsonAudio(content->audio_.get(), client_)); - add_caption(object, content->caption_); + add_caption(object, content->caption_, false); break; } case td_api::messageDocument::ID: { auto content = static_cast(message_->content.get()); object("document", JsonDocument(content->document_.get(), client_)); - add_caption(object, content->caption_); + add_caption(object, content->caption_, false); break; } case td_api::messagePhoto::ID: { auto content = static_cast(message_->content.get()); CHECK(content->photo_ != nullptr); object("photo", JsonPhoto(content->photo_.get(), client_)); - add_caption(object, content->caption_); + add_caption(object, content->caption_, content->show_caption_above_media_); add_media_spoiler(object, content->has_spoiler_); break; } @@ -2846,7 +2851,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { case td_api::messageVideo::ID: { auto content = static_cast(message_->content.get()); object("video", JsonVideo(content->video_.get(), client_)); - add_caption(object, content->caption_); + add_caption(object, content->caption_, content->show_caption_above_media_); add_media_spoiler(object, content->has_spoiler_); break; } @@ -2858,7 +2863,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { case td_api::messageVoiceNote::ID: { auto content = static_cast(message_->content.get()); object("voice", JsonVoiceNote(content->voice_note_.get(), client_)); - add_caption(object, content->caption_); + add_caption(object, content->caption_, false); break; } case td_api::messageContact::ID: { From 7d7b4049a4de53dba66a24615ecd8921895e6ea1 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 20 May 2024 14:41:19 +0300 Subject: [PATCH 102/162] Allow adding effects to sent messages. --- telegram-bot-api/Client.cpp | 52 ++++++++++++++++++++----------------- telegram-bot-api/Client.h | 2 +- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 025f847..20b98b1 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -7725,9 +7725,9 @@ td::Result> Client::get_input_me } td_api::object_ptr Client::get_message_send_options(bool disable_notification, - bool protect_content) { - return make_object(disable_notification, false, protect_content, false, nullptr, 0, 0, - false); + bool protect_content, int64 effect_id) { + return make_object(disable_notification, false, protect_content, false, nullptr, + effect_id, 0, false); } td::Result> Client::get_inline_query_results_button( @@ -10059,7 +10059,7 @@ td::Status Client::process_copy_messages_query(PromisedQueryPtr &query) { 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), + get_message_send_options(disable_notification, protect_content, 0), true, remove_caption), td::make_unique(this, chat_id, message_count, std::move(query))); }); }; @@ -10113,7 +10113,7 @@ td::Status Client::process_forward_messages_query(PromisedQueryPtr &query) { 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), + get_message_send_options(disable_notification, protect_content, 0), false, false), td::make_unique(this, chat_id, message_count, std::move(query))); }); }; @@ -10129,6 +10129,7 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { auto business_connection_id = query->arg("business_connection_id"); auto disable_notification = to_bool(query->arg("disable_notification")); auto protect_content = to_bool(query->arg("protect_content")); + auto effect_id = td::to_integer(query->arg("message_effect_id")); // TRY_RESULT(reply_markup, get_reply_markup(query.get(), bot_user_ids_)); auto reply_markup = nullptr; TRY_RESULT(input_message_contents, get_input_message_contents(query.get(), "media")); @@ -10136,7 +10137,7 @@ 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_str = chat_id.str(), message_thread_id, business_connection_id = business_connection_id.str(), - reply_parameters = std::move(reply_parameters), disable_notification, protect_content, + reply_parameters = std::move(reply_parameters), disable_notification, protect_content, effect_id, input_message_contents = std::move(input_message_contents)](object_ptr reply_markup, PromisedQueryPtr query) mutable { if (!business_connection_id.empty()) { @@ -10148,18 +10149,19 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { return check_business_connection( business_connection_id, std::move(query), [this, chat_id, reply_parameters = std::move(reply_parameters), disable_notification, protect_content, - input_message_contents = std::move(input_message_contents), reply_markup = std::move(reply_markup)]( - const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { + effect_id, input_message_contents = std::move(input_message_contents), + reply_markup = std::move(reply_markup)](const BusinessConnection *business_connection, + PromisedQueryPtr query) mutable { send_request( make_object( business_connection->id_, chat_id, get_input_message_reply_to(std::move(reply_parameters)), - disable_notification, protect_content, 0, std::move(input_message_contents)), + disable_notification, protect_content, effect_id, std::move(input_message_contents)), td::make_unique(this, business_connection->id_, std::move(query))); }); } - auto on_success = [this, disable_notification, protect_content, + auto on_success = [this, disable_notification, protect_content, effect_id, input_message_contents = std::move(input_message_contents), reply_markup = std::move(reply_markup)](int64 chat_id, int64 message_thread_id, CheckedReplyParameters reply_parameters, @@ -10171,11 +10173,11 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &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(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))); + 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, effect_id), + std::move(input_message_contents)), + td::make_unique(this, chat_id, message_count, std::move(query))); }; check_reply_parameters(chat_id_str, std::move(reply_parameters), message_thread_id, std::move(query), std::move(on_success)); @@ -11973,6 +11975,7 @@ void Client::do_send_message(object_ptr input_messa 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 effect_id = td::to_integer(query->arg("message_effect_id")); auto r_reply_markup = get_reply_markup(query.get(), bot_user_ids_); if (r_reply_markup.is_error()) { return fail_query_with_error(std::move(query), 400, r_reply_markup.error().message()); @@ -11982,7 +11985,7 @@ void Client::do_send_message(object_ptr input_messa resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), [this, chat_id_str = chat_id.str(), message_thread_id, business_connection_id = business_connection_id.str(), - reply_parameters = std::move(reply_parameters), disable_notification, protect_content, + reply_parameters = std::move(reply_parameters), disable_notification, protect_content, effect_id, input_message_content = std::move(input_message_content)](object_ptr reply_markup, PromisedQueryPtr query) mutable { if (!business_connection_id.empty()) { @@ -11994,18 +11997,19 @@ void Client::do_send_message(object_ptr input_messa return check_business_connection( business_connection_id, std::move(query), [this, chat_id, reply_parameters = std::move(reply_parameters), disable_notification, protect_content, - reply_markup = std::move(reply_markup), input_message_content = std::move(input_message_content)]( - const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { + effect_id, reply_markup = std::move(reply_markup), + input_message_content = std::move(input_message_content)](const BusinessConnection *business_connection, + PromisedQueryPtr query) mutable { send_request( make_object(business_connection->id_, chat_id, get_input_message_reply_to(std::move(reply_parameters)), - disable_notification, protect_content, 0, + disable_notification, protect_content, effect_id, std::move(reply_markup), std::move(input_message_content)), td::make_unique(this, business_connection->id_, std::move(query))); }); } - auto on_success = [this, disable_notification, protect_content, + auto on_success = [this, disable_notification, protect_content, effect_id, input_message_content = std::move(input_message_content), reply_markup = std::move(reply_markup)](int64 chat_id, int64 message_thread_id, CheckedReplyParameters reply_parameters, @@ -12016,10 +12020,10 @@ void Client::do_send_message(object_ptr input_messa } count++; - 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)), + 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, effect_id), + std::move(reply_markup), std::move(input_message_content)), td::make_unique(this, chat_id, std::move(query))); }; check_reply_parameters(chat_id_str, std::move(reply_parameters), message_thread_id, std::move(query), diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index f37d537..7bcffe9 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -561,7 +561,7 @@ class Client final : public WebhookActor::Callback { td::Result> get_input_message_invoice(const Query *query) const; static object_ptr get_message_send_options(bool disable_notification, - bool protect_content); + bool protect_content, int64 effect_id); static td::Result>> get_poll_options(const Query *query); From 5f3e2202b7777711d9277a861d902306f0ed77cc Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 20 May 2024 14:48:41 +0300 Subject: [PATCH 103/162] Allow to send messages with caption above media. --- telegram-bot-api/Client.cpp | 49 +++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 20b98b1..8963645 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -7879,6 +7879,7 @@ td::Result> Client::get_inlin TRY_RESULT(parse_mode, object.get_optional_string_field("parse_mode")); auto entities = object.extract_field("caption_entities"); TRY_RESULT(caption, get_formatted_text(std::move(input_caption), std::move(parse_mode), std::move(entities))); + TRY_RESULT(show_caption_above_media, object.get_optional_bool_field("show_caption_above_media")); TRY_RESULT(reply_markup_object, object.extract_optional_field("reply_markup", td::JsonValue::Type::Object)); object_ptr reply_markup; @@ -7979,8 +7980,9 @@ td::Result> Client::get_inlin } if (input_message_content == nullptr) { - input_message_content = make_object( - nullptr, nullptr, td::vector(), gif_duration, gif_width, gif_height, std::move(caption), false, false); + input_message_content = + make_object(nullptr, nullptr, td::vector(), gif_duration, gif_width, + gif_height, std::move(caption), show_caption_above_media, false); } return make_object( id, title, thumbnail_url, thumbnail_mime_type, gif_url, "image/gif", gif_duration, gif_width, gif_height, @@ -8022,7 +8024,7 @@ td::Result> Client::get_inlin if (input_message_content == nullptr) { input_message_content = make_object(nullptr, nullptr, td::vector(), mpeg4_duration, mpeg4_width, - mpeg4_height, std::move(caption), false, false); + mpeg4_height, std::move(caption), show_caption_above_media, false); } return make_object( id, title, thumbnail_url, thumbnail_mime_type, mpeg4_url, "video/mp4", mpeg4_duration, mpeg4_width, @@ -8039,8 +8041,8 @@ td::Result> Client::get_inlin } if (input_message_content == nullptr) { - input_message_content = make_object(nullptr, nullptr, td::vector(), 0, 0, - std::move(caption), false, nullptr, false); + input_message_content = make_object( + nullptr, nullptr, td::vector(), 0, 0, std::move(caption), show_caption_above_media, nullptr, false); } return make_object(id, title, description, thumbnail_url, photo_url, photo_width, photo_height, std::move(reply_markup), @@ -8105,9 +8107,9 @@ td::Result> Client::get_inlin } if (input_message_content == nullptr) { - input_message_content = - make_object(nullptr, nullptr, td::vector(), video_duration, video_width, - video_height, false, std::move(caption), false, nullptr, false); + input_message_content = make_object( + nullptr, nullptr, td::vector(), video_duration, video_width, video_height, false, std::move(caption), + show_caption_above_media, nullptr, false); } return make_object(id, title, description, thumbnail_url, video_url, mime_type, video_width, video_height, video_duration, @@ -9070,6 +9072,7 @@ td::Result> Client::get_input_me TRY_RESULT(parse_mode, object.get_optional_string_field("parse_mode")); auto entities = object.extract_field("caption_entities"); TRY_RESULT(caption, get_formatted_text(std::move(input_caption), std::move(parse_mode), std::move(entities))); + TRY_RESULT(show_caption_above_media, object.get_optional_bool_field("show_caption_above_media")); TRY_RESULT(has_spoiler, object.get_optional_bool_field("has_spoiler")); TRY_RESULT(media, object.get_optional_string_field("media")); @@ -9097,7 +9100,7 @@ td::Result> Client::get_input_me TRY_RESULT(type, object.get_required_string_field("type")); if (type == "photo") { return make_object(std::move(input_file), nullptr, td::vector(), 0, 0, - std::move(caption), false, nullptr, has_spoiler); + std::move(caption), show_caption_above_media, nullptr, has_spoiler); } if (type == "video") { TRY_RESULT(width, object.get_optional_int_field("width")); @@ -9110,7 +9113,7 @@ td::Result> Client::get_input_me return make_object(std::move(input_file), std::move(input_thumbnail), td::vector(), duration, width, height, supports_streaming, - std::move(caption), false, nullptr, has_spoiler); + std::move(caption), show_caption_above_media, nullptr, has_spoiler); } if (for_album && type == "animation") { return td::Status::Error(PSLICE() << "type \"" << type << "\" can't be used in sendMediaGroup"); @@ -9124,7 +9127,7 @@ td::Result> Client::get_input_me duration = td::clamp(duration, 0, MAX_DURATION); return make_object(std::move(input_file), std::move(input_thumbnail), td::vector(), duration, width, height, std::move(caption), - false, has_spoiler); + show_caption_above_media, has_spoiler); } if (type == "audio") { TRY_RESULT(duration, object.get_optional_int_field("duration")); @@ -9774,11 +9777,12 @@ td::Status Client::process_send_animation_query(PromisedQueryPtr &query) { int32 width = get_integer_arg(query.get(), "width", 0, 0, MAX_LENGTH); int32 height = get_integer_arg(query.get(), "height", 0, 0, MAX_LENGTH); TRY_RESULT(caption, get_caption(query.get())); + auto show_caption_above_media = to_bool(query->arg("show_caption_above_media")); auto has_spoiler = to_bool(query->arg("has_spoiler")); - do_send_message( - make_object(std::move(animation), std::move(thumbnail), td::vector(), - duration, width, height, std::move(caption), false, has_spoiler), - std::move(query)); + do_send_message(make_object(std::move(animation), std::move(thumbnail), + td::vector(), duration, width, height, + std::move(caption), show_caption_above_media, has_spoiler), + std::move(query)); return td::Status::OK(); } @@ -9824,10 +9828,12 @@ td::Status Client::process_send_photo_query(PromisedQueryPtr &query) { return td::Status::Error(400, "There is no photo in the request"); } TRY_RESULT(caption, get_caption(query.get())); + auto show_caption_above_media = to_bool(query->arg("show_caption_above_media")); auto has_spoiler = to_bool(query->arg("has_spoiler")); - do_send_message(make_object(std::move(photo), nullptr, td::vector(), 0, 0, - std::move(caption), false, nullptr, has_spoiler), - std::move(query)); + do_send_message( + make_object(std::move(photo), nullptr, td::vector(), 0, 0, std::move(caption), + show_caption_above_media, nullptr, has_spoiler), + std::move(query)); return td::Status::OK(); } @@ -9853,10 +9859,11 @@ td::Status Client::process_send_video_query(PromisedQueryPtr &query) { int32 height = get_integer_arg(query.get(), "height", 0, 0, MAX_LENGTH); bool supports_streaming = to_bool(query->arg("supports_streaming")); TRY_RESULT(caption, get_caption(query.get())); + auto show_caption_above_media = to_bool(query->arg("show_caption_above_media")); auto has_spoiler = to_bool(query->arg("has_spoiler")); - do_send_message(make_object(std::move(video), std::move(thumbnail), td::vector(), - duration, width, height, supports_streaming, - std::move(caption), false, nullptr, has_spoiler), + do_send_message(make_object( + std::move(video), std::move(thumbnail), td::vector(), duration, width, height, + supports_streaming, std::move(caption), show_caption_above_media, nullptr, has_spoiler), std::move(query)); return td::Status::OK(); } From f32756cd0d1b4c50ed124199f339d7eb7c776f42 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 20 May 2024 14:54:17 +0300 Subject: [PATCH 104/162] Allow to edit show_caption_above_media. --- telegram-bot-api/Client.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 8963645..721e8a1 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -10352,28 +10352,30 @@ td::Status Client::process_edit_message_caption_query(PromisedQueryPtr &query) { auto message_id = get_message_id(query.get()); TRY_RESULT(reply_markup, get_reply_markup(query.get(), bot_user_ids_)); TRY_RESULT(caption, get_caption(query.get())); + auto show_caption_above_media = to_bool(query->arg("show_caption_above_media")); if (chat_id.empty() && message_id == 0) { TRY_RESULT(inline_message_id, get_inline_message_id(query.get())); resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, inline_message_id = inline_message_id.str(), caption = std::move(caption)]( + [this, inline_message_id = inline_message_id.str(), caption = std::move(caption), show_caption_above_media]( object_ptr reply_markup, PromisedQueryPtr query) mutable { send_request(make_object(inline_message_id, std::move(reply_markup), - std::move(caption), false), + std::move(caption), show_caption_above_media), td::make_unique(std::move(query))); }); } else { resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, chat_id = chat_id.str(), message_id, caption = std::move(caption)]( + [this, chat_id = chat_id.str(), message_id, caption = std::move(caption), show_caption_above_media]( object_ptr reply_markup, PromisedQueryPtr query) mutable { check_message(chat_id, message_id, false, AccessRights::Edit, "message to edit", std::move(query), - [this, reply_markup = std::move(reply_markup), caption = std::move(caption)]( - int64 chat_id, int64 message_id, PromisedQueryPtr query) mutable { - send_request(make_object( - chat_id, message_id, std::move(reply_markup), std::move(caption), false), - td::make_unique(this, std::move(query))); + [this, reply_markup = std::move(reply_markup), caption = std::move(caption), + show_caption_above_media](int64 chat_id, int64 message_id, PromisedQueryPtr query) mutable { + send_request( + make_object(chat_id, message_id, std::move(reply_markup), + std::move(caption), show_caption_above_media), + td::make_unique(this, std::move(query))); }); }); } From 34a52855ee17a7f010698a86ee8a4d48dc1139dc Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 20 May 2024 14:54:53 +0300 Subject: [PATCH 105/162] Allow to change show_caption_above_media when replacing caption of a copied 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 721e8a1..a51594b 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -10020,7 +10020,9 @@ td::Status Client::process_copy_message_query(PromisedQueryPtr &query) { if (replace_caption) { TRY_RESULT_ASSIGN(caption, get_caption(query.get())); } - auto options = make_object(true, replace_caption, std::move(caption), false); + auto show_caption_above_media = to_bool(query->arg("show_caption_above_media")); + auto options = + make_object(true, replace_caption, std::move(caption), show_caption_above_media); check_message( from_chat_id, message_id, false, AccessRights::Read, "message to copy", std::move(query), From 70b9d04b5878d79af756782421f7180a204c26fe Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 20 May 2024 15:05:46 +0300 Subject: [PATCH 106/162] Make provider_token optional for invoices in Telegram Stars. --- 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 a51594b..81fe4f0 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -7685,7 +7685,7 @@ td::Result> Client::get_input_me if (!td::check_utf8(payload)) { return td::Status::Error(400, "InputInvoiceMessageContent payload must be encoded in UTF-8"); } - TRY_RESULT(provider_token, object.get_required_string_field("provider_token")); + TRY_RESULT(provider_token, object.get_optional_string_field("provider_token")); TRY_RESULT(currency, object.get_required_string_field("currency")); TRY_RESULT(prices_object, object.extract_required_field("prices", td::JsonValue::Type::Array)); TRY_RESULT(prices, get_labeled_price_parts(prices_object)); @@ -9204,7 +9204,7 @@ td::Result> Client::get_input_me if (!td::check_utf8(payload.str())) { return td::Status::Error(400, "The payload must be encoded in UTF-8"); } - TRY_RESULT(provider_token, get_required_string_arg(query, "provider_token")); + auto provider_token = query->arg("provider_token"); auto provider_data = query->arg("provider_data"); auto start_parameter = query->arg("start_parameter"); TRY_RESULT(currency, get_required_string_arg(query, "currency")); From 325dc5d2934920328f6cf8a3af8c05ed627f7cdd Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 21 May 2024 12:39:13 +0300 Subject: [PATCH 107/162] Support expandable_blockquote entities. --- 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 81fe4f0..83a7f16 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -523,6 +523,9 @@ class Client::JsonEntity final : public td::Jsonable { case td_api::textEntityTypeBlockQuote::ID: object("type", "blockquote"); break; + case td_api::textEntityTypeExpandableBlockQuote::ID: + object("type", "expandable_blockquote"); + break; default: UNREACHABLE(); } @@ -542,8 +545,7 @@ class Client::JsonVectorEntities final : public td::Jsonable { auto array = scope->enter_array(); for (auto &entity : entities_) { auto entity_type = entity->type_->get_id(); - if (entity_type != td_api::textEntityTypeExpandableBlockQuote::ID && - entity_type != td_api::textEntityTypeBankCardNumber::ID && + if (entity_type != td_api::textEntityTypeBankCardNumber::ID && entity_type != td_api::textEntityTypeMediaTimestamp::ID) { array << JsonEntity(entity.get(), client_); } @@ -8792,6 +8794,9 @@ td::Result> Client::get_text_entity_t if (type == "blockquote") { return make_object(); } + if (type == "expandable_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 486539c51471997d704e5db7297682beae1b6696 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 24 May 2024 15:44:38 +0300 Subject: [PATCH 108/162] Add refundStarPayment method. --- telegram-bot-api/Client.cpp | 13 +++++++++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 14 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 83a7f16..142dc26 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -246,6 +246,7 @@ bool Client::init_methods() { 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("refundstarpayment", &Client::process_refund_star_payment_query); methods_.emplace("setgamescore", &Client::process_set_game_score_query); methods_.emplace("getgamehighscores", &Client::process_get_game_high_scores_query); methods_.emplace("answerwebappquery", &Client::process_answer_web_app_query_query); @@ -10461,6 +10462,18 @@ td::Status Client::process_create_invoice_link_query(PromisedQueryPtr &query) { return td::Status::OK(); } +td::Status Client::process_refund_star_payment_query(PromisedQueryPtr &query) { + TRY_RESULT(user_id, get_user_id(query.get())); + TRY_RESULT(telegram_payment_charge_id, get_required_string_arg(query.get(), "telegram_payment_charge_id")); + check_user_no_fail( + user_id, std::move(query), + [this, telegram_payment_charge_id = telegram_payment_charge_id.str(), user_id](PromisedQueryPtr query) { + send_request(make_object(user_id, telegram_payment_charge_id), + td::make_unique(std::move(query))); + }); + return td::Status::OK(); +} + td::Status Client::process_set_game_score_query(PromisedQueryPtr &query) { auto chat_id = query->arg("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 7bcffe9..4e0bc74 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -647,6 +647,7 @@ class Client final : public WebhookActor::Callback { 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_refund_star_payment_query(PromisedQueryPtr &query); td::Status process_set_game_score_query(PromisedQueryPtr &query); td::Status process_get_game_high_scores_query(PromisedQueryPtr &query); td::Status process_answer_web_app_query_query(PromisedQueryPtr &query); From 831968def2449efd9bbf630d8bd0296fa456db2d Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 28 May 2024 00:11:50 +0300 Subject: [PATCH 109/162] Update version to 7.4. --- 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 276606d..b7b9380 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 7.3 LANGUAGES CXX) +project(TelegramBotApi VERSION 7.4 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 f66a522..0538d9c 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.3"; + parameters->version_ = "7.4"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats(); From a94b95eac5d81c93e44a659dbc5d315b07729317 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 30 May 2024 19:40:54 +0300 Subject: [PATCH 110/162] Update copyright year. --- telegram-bot-api/Client.cpp | 2 +- telegram-bot-api/Client.h | 2 +- telegram-bot-api/ClientManager.cpp | 2 +- telegram-bot-api/ClientManager.h | 2 +- telegram-bot-api/ClientParameters.h | 2 +- telegram-bot-api/HttpConnection.cpp | 2 +- telegram-bot-api/HttpConnection.h | 2 +- telegram-bot-api/HttpServer.h | 2 +- telegram-bot-api/HttpStatConnection.cpp | 2 +- telegram-bot-api/HttpStatConnection.h | 2 +- telegram-bot-api/Query.cpp | 2 +- telegram-bot-api/Query.h | 2 +- telegram-bot-api/Stats.cpp | 2 +- telegram-bot-api/Stats.h | 2 +- telegram-bot-api/Watchdog.cpp | 2 +- telegram-bot-api/Watchdog.h | 2 +- telegram-bot-api/WebhookActor.cpp | 2 +- telegram-bot-api/WebhookActor.h | 2 +- telegram-bot-api/telegram-bot-api.cpp | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 142dc26..bd5874e 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 4e0bc74..58b234e 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/ClientManager.cpp b/telegram-bot-api/ClientManager.cpp index 68338fd..5b6f454 100644 --- a/telegram-bot-api/ClientManager.cpp +++ b/telegram-bot-api/ClientManager.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/ClientManager.h b/telegram-bot-api/ClientManager.h index ef91214..8d4e2d6 100644 --- a/telegram-bot-api/ClientManager.h +++ b/telegram-bot-api/ClientManager.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/ClientParameters.h b/telegram-bot-api/ClientParameters.h index b8558f9..fac9b77 100644 --- a/telegram-bot-api/ClientParameters.h +++ b/telegram-bot-api/ClientParameters.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/HttpConnection.cpp b/telegram-bot-api/HttpConnection.cpp index ade03d3..52a9823 100644 --- a/telegram-bot-api/HttpConnection.cpp +++ b/telegram-bot-api/HttpConnection.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/HttpConnection.h b/telegram-bot-api/HttpConnection.h index 0e3b39c..b66b062 100644 --- a/telegram-bot-api/HttpConnection.h +++ b/telegram-bot-api/HttpConnection.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/HttpServer.h b/telegram-bot-api/HttpServer.h index c2398ee..21c26a8 100644 --- a/telegram-bot-api/HttpServer.h +++ b/telegram-bot-api/HttpServer.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/HttpStatConnection.cpp b/telegram-bot-api/HttpStatConnection.cpp index d01af06..574b8bd 100644 --- a/telegram-bot-api/HttpStatConnection.cpp +++ b/telegram-bot-api/HttpStatConnection.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/HttpStatConnection.h b/telegram-bot-api/HttpStatConnection.h index b653326..b699ba7 100644 --- a/telegram-bot-api/HttpStatConnection.h +++ b/telegram-bot-api/HttpStatConnection.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/Query.cpp b/telegram-bot-api/Query.cpp index 39a59da..66d2b5a 100644 --- a/telegram-bot-api/Query.cpp +++ b/telegram-bot-api/Query.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/Query.h b/telegram-bot-api/Query.h index 5044ce0..bcf5ef7 100644 --- a/telegram-bot-api/Query.h +++ b/telegram-bot-api/Query.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/Stats.cpp b/telegram-bot-api/Stats.cpp index d682610..2190644 100644 --- a/telegram-bot-api/Stats.cpp +++ b/telegram-bot-api/Stats.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/Stats.h b/telegram-bot-api/Stats.h index 3871053..dedd3df 100644 --- a/telegram-bot-api/Stats.h +++ b/telegram-bot-api/Stats.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/Watchdog.cpp b/telegram-bot-api/Watchdog.cpp index 9b5c88d..98c7ff2 100644 --- a/telegram-bot-api/Watchdog.cpp +++ b/telegram-bot-api/Watchdog.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/Watchdog.h b/telegram-bot-api/Watchdog.h index 89ac3c6..c34eb2d 100644 --- a/telegram-bot-api/Watchdog.h +++ b/telegram-bot-api/Watchdog.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/WebhookActor.cpp b/telegram-bot-api/WebhookActor.cpp index 3e0caa0..6968bc2 100644 --- a/telegram-bot-api/WebhookActor.cpp +++ b/telegram-bot-api/WebhookActor.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/WebhookActor.h b/telegram-bot-api/WebhookActor.h index 4c101a3..610a30b 100644 --- a/telegram-bot-api/WebhookActor.h +++ b/telegram-bot-api/WebhookActor.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index 0538d9c..6bc71fb 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) From 221db0fa1f5c695cd020f9ec388f03ce85c855ef Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 30 May 2024 19:47:21 +0300 Subject: [PATCH 111/162] Improve getUpdates warnings. --- telegram-bot-api/Client.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index bd5874e..b9cebed 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -12225,7 +12225,7 @@ void Client::do_get_updates(int32 offset, int32 limit, int32 timeout, PromisedQu CHECK(total_size >= updates.size()); total_size -= updates.size(); - bool need_warning = total_size > 0 && (query->start_timestamp() - previous_get_updates_finish_time_ > 10.0); + bool need_warning = total_size > 0 && (query->start_timestamp() - previous_get_updates_finish_time_ > 5.0); if (total_size <= MIN_PENDING_UPDATES_WARNING / 2) { if (last_pending_update_count_ > MIN_PENDING_UPDATES_WARNING) { need_warning = true; @@ -12237,7 +12237,8 @@ void Client::do_get_updates(int32 offset, int32 limit, int32 timeout, PromisedQu last_pending_update_count_ *= 2; } } - if (need_warning && previous_get_updates_finish_time_ > 0) { + if (need_warning && previous_get_updates_finish_time_ > 0 && + query->start_timestamp() > previous_get_updates_finish_time_) { LOG(WARNING) << "Found " << updates.size() << " updates out of " << (total_size + updates.size()) << " after last getUpdates call " << (query->start_timestamp() - previous_get_updates_finish_time_) << " seconds ago in " << (td::Time::now() - query->start_timestamp()) << " seconds from " From 2b0bb9207c55d440bb01bde157b41009330319f7 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 6 Jun 2024 13:57:02 +0300 Subject: [PATCH 112/162] Split "chat_member" and "chat_join_request" updates by a user. --- 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 b9cebed..aec8ce0 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -12963,7 +12963,7 @@ void Client::add_update_chat_member(object_ptr &&updat } auto user_id = static_cast(update->old_chat_member_->member_id_.get())->user_id_; bool is_my = (user_id == my_id_); - auto webhook_queue_id = update->chat_id_ + (static_cast(is_my ? 5 : 6) << 33); + auto webhook_queue_id = (is_my ? update->chat_id_ : user_id) + (static_cast(is_my ? 5 : 6) << 33); auto update_type = is_my ? UpdateType::MyChatMember : UpdateType::ChatMember; add_update(update_type, JsonChatMemberUpdated(update.get(), this), left_time, webhook_queue_id); } else { @@ -12977,7 +12977,7 @@ void Client::add_update_chat_join_request(object_ptrrequest_ != nullptr); auto left_time = update->request_->date_ + 86400 - get_unix_time(); if (left_time > 0) { - auto webhook_queue_id = update->chat_id_ + (static_cast(6) << 33); + auto webhook_queue_id = update->request_->user_id_ + (static_cast(6) << 33); add_update(UpdateType::ChatJoinRequest, JsonChatJoinRequest(update.get(), this), left_time, webhook_queue_id); } else { LOG(DEBUG) << "Skip updateNewChatJoinRequest with date " << update->request_->date_ << ", because current date is " From d982389d773059d917dedb623e23cd82ffc2ef8d Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 11 Jun 2024 21:42:50 +0300 Subject: [PATCH 113/162] Update TDLib to 1.8.31. --- td | 2 +- telegram-bot-api/Client.cpp | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/td b/td index fab354a..8f19c75 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit fab354add5a257a8121a4a7f1ff6b1b9fa9a9073 +Subproject commit 8f19c751dc296cedb9a921badb7a02a8c0cb1aeb diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index aec8ce0..a1a5440 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -7011,8 +7011,12 @@ 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( - reply_parameters.reply_in_chat_id, reply_parameters.reply_to_message_id, std::move(reply_parameters.quote)); + if (reply_parameters.reply_in_chat_id != 0) { + return make_object( + reply_parameters.reply_in_chat_id, reply_parameters.reply_to_message_id, std::move(reply_parameters.quote)); + } + return make_object(reply_parameters.reply_to_message_id, + std::move(reply_parameters.quote)); } return nullptr; } @@ -7020,7 +7024,7 @@ td_api::object_ptr Client::get_input_message_reply_ td_api::object_ptr Client::get_input_message_reply_to( InputReplyParameters &&reply_parameters) { if (reply_parameters.reply_in_chat_id.empty() && reply_parameters.reply_to_message_id > 0) { - return make_object(0, reply_parameters.reply_to_message_id, + return make_object(reply_parameters.reply_to_message_id, std::move(reply_parameters.quote)); } return nullptr; From e2af6c8e021d7a85509fab4ddd2990db312ff5d3 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 11 Jun 2024 22:07:13 +0300 Subject: [PATCH 114/162] Add callback query updates from business messages. --- telegram-bot-api/Client.cpp | 99 ++++++++++++++++++++++++++++++++----- telegram-bot-api/Client.h | 12 ++++- 2 files changed, 98 insertions(+), 13 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index a1a5440..fd1a290 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4839,12 +4839,14 @@ class Client::TdOnGetCallbackQueryMessageCallback final : public TdQueryCallback class Client::TdOnGetStickerSetCallback final : public TdQueryCallback { public: TdOnGetStickerSetCallback(Client *client, int64 set_id, int64 new_callback_query_user_id, int64 new_message_chat_id, - const td::string &new_message_business_connection_id) + const td::string &new_message_business_connection_id, + int64 new_business_callback_query_user_id) : client_(client) , set_id_(set_id) , new_callback_query_user_id_(new_callback_query_user_id) , new_message_chat_id_(new_message_chat_id) - , new_message_business_connection_id_(new_message_business_connection_id) { + , new_message_business_connection_id_(new_message_business_connection_id) + , new_business_callback_query_user_id_(new_business_callback_query_user_id) { } void on_result(object_ptr result) final { @@ -4856,12 +4858,14 @@ class Client::TdOnGetStickerSetCallback final : public TdQueryCallback { << td::oneline(to_string(error)); } return client_->on_get_sticker_set(set_id_, new_callback_query_user_id_, new_message_chat_id_, - new_message_business_connection_id_, nullptr); + new_message_business_connection_id_, new_business_callback_query_user_id_, + nullptr); } CHECK(result->get_id() == td_api::stickerSet::ID); client_->on_get_sticker_set(set_id_, new_callback_query_user_id_, new_message_chat_id_, - new_message_business_connection_id_, move_object_as(result)); + new_message_business_connection_id_, new_business_callback_query_user_id_, + move_object_as(result)); } private: @@ -4870,6 +4874,7 @@ class Client::TdOnGetStickerSetCallback final : public TdQueryCallback { int64 new_callback_query_user_id_; int64 new_message_chat_id_; td::string new_message_business_connection_id_; + int64 new_business_callback_query_user_id_; }; class Client::TdOnGetChatCustomEmojiStickerSetCallback final : public TdQueryCallback { @@ -5800,7 +5805,7 @@ void Client::on_get_callback_query_message(object_ptr message, void Client::on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, int64 new_message_chat_id, const td::string &new_message_business_connection_id, - object_ptr sticker_set) { + int64 new_business_callback_query_user_id, object_ptr sticker_set) { if (new_callback_query_user_id != 0) { auto &queue = new_callback_query_queues_[new_callback_query_user_id]; CHECK(queue.has_active_request_); @@ -5822,6 +5827,13 @@ void Client::on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, CHECK(!queue.queue_.empty()); } + if (new_business_callback_query_user_id != 0) { + auto &queue = new_business_callback_query_queues_[new_business_callback_query_user_id]; + CHECK(queue.has_active_request_); + queue.has_active_request_ = false; + + CHECK(!queue.queue_.empty()); + } CHECK(set_id != 0); if (set_id != GREAT_MINDS_SET_ID) { @@ -5840,6 +5852,9 @@ void Client::on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, if (!new_message_business_connection_id.empty()) { process_new_business_message_queue(new_message_business_connection_id); } + if (new_business_callback_query_user_id != 0) { + process_new_business_callback_query_queue(new_business_callback_query_user_id); + } } void Client::on_get_sticker_set_name(int64 set_id, const td::string &name) { @@ -6822,6 +6837,9 @@ void Client::on_update(object_ptr result) { case td_api::updateNewCallbackQuery::ID: add_new_callback_query(move_object_as(result)); break; + case td_api::updateNewBusinessCallbackQuery::ID: + add_new_business_callback_query(move_object_as(result)); + break; case td_api::updateNewInlineCallbackQuery::ID: add_new_inline_callback_query(move_object_as(result)); break; @@ -12896,7 +12914,7 @@ void Client::process_new_callback_query_queue(int64 user_id, int state) { queue.has_active_request_ = true; return send_request( make_object(message_sticker_set_id), - td::make_unique(this, message_sticker_set_id, user_id, 0, td::string())); + td::make_unique(this, message_sticker_set_id, user_id, 0, td::string(), 0)); } auto reply_to_message_id = get_same_chat_reply_to_message_id(message_info); if (reply_to_message_id > 0) { @@ -12907,7 +12925,7 @@ void Client::process_new_callback_query_queue(int64 user_id, int state) { queue.has_active_request_ = true; return send_request( make_object(reply_sticker_set_id), - td::make_unique(this, reply_sticker_set_id, user_id, 0, td::string())); + td::make_unique(this, reply_sticker_set_id, user_id, 0, td::string(), 0)); } } } @@ -12925,6 +12943,63 @@ void Client::process_new_callback_query_queue(int64 user_id, int state) { new_callback_query_queues_.erase(user_id); } +void Client::add_new_business_callback_query(object_ptr &&query) { + CHECK(query != nullptr); + auto user_id = query->sender_user_id_; + CHECK(user_id != 0); + new_business_callback_query_queues_[user_id].queue_.push(std::move(query)); + process_new_business_callback_query_queue(user_id); +} + +void Client::process_new_business_callback_query_queue(int64 user_id) { + auto &queue = new_business_callback_query_queues_[user_id]; + if (queue.has_active_request_) { + CHECK(!queue.queue_.empty()); + LOG(INFO) << "Have an active request in business callback query queue of size " << queue.queue_.size() + << " for user " << user_id; + return; + } + if (logging_out_ || closing_) { + LOG(INFO) << "Ignore business callback query while closing for user " << user_id; + new_business_callback_query_queues_.erase(user_id); + return; + } + while (!queue.queue_.empty()) { + auto &query = queue.queue_.front(); + auto &message_ref = query->message_; + LOG(INFO) << "Process business callback query from user " << user_id; + + drop_internal_reply_to_message_in_another_chat(message_ref->message_); + + auto message_sticker_set_id = get_sticker_set_id(message_ref->message_->content_); + if (!have_sticker_set_name(message_sticker_set_id)) { + queue.has_active_request_ = true; + return send_request( + make_object(message_sticker_set_id), + td::make_unique(this, message_sticker_set_id, 0, 0, td::string(), user_id)); + } + if (message_ref->reply_to_message_ != nullptr) { + drop_internal_reply_to_message_in_another_chat(message_ref->reply_to_message_); + auto reply_sticker_set_id = get_sticker_set_id(message_ref->reply_to_message_->content_); + if (!have_sticker_set_name(reply_sticker_set_id)) { + queue.has_active_request_ = true; + return send_request( + make_object(reply_sticker_set_id), + td::make_unique(this, reply_sticker_set_id, 0, 0, td::string(), user_id)); + } + } + + CHECK(user_id == query->sender_user_id_); + auto message_info = create_business_message(query->connection_id_, std::move(message_ref)); + add_update(UpdateType::CallbackQuery, + JsonCallbackQuery(query->id_, user_id, 0, 0, message_info.get(), query->chat_instance_, + query->payload_.get(), this), + 150, user_id + (static_cast(3) << 33)); + queue.queue_.pop(); + } + new_callback_query_queues_.erase(user_id); +} + void Client::add_new_inline_callback_query(object_ptr &&query) { CHECK(query != nullptr); add_update(UpdateType::CallbackQuery, @@ -13481,7 +13556,7 @@ void Client::process_new_message_queue(int64 chat_id, int state) { queue.has_active_request_ = true; return send_request( make_object(message_sticker_set_id), - td::make_unique(this, message_sticker_set_id, 0, chat_id, td::string())); + td::make_unique(this, message_sticker_set_id, 0, chat_id, td::string(), 0)); } if (reply_to_message_id > 0) { auto reply_to_message_info = get_message(chat_id, reply_to_message_id, true); @@ -13491,7 +13566,7 @@ void Client::process_new_message_queue(int64 chat_id, int state) { queue.has_active_request_ = true; return send_request( make_object(reply_sticker_set_id), - td::make_unique(this, reply_sticker_set_id, 0, chat_id, td::string())); + td::make_unique(this, reply_sticker_set_id, 0, chat_id, td::string(), 0)); } } } @@ -13581,7 +13656,7 @@ void Client::process_new_business_message_queue(const td::string &connection_id) queue.has_active_request_ = true; return send_request( make_object(message_sticker_set_id), - td::make_unique(this, message_sticker_set_id, 0, 0, connection_id)); + td::make_unique(this, message_sticker_set_id, 0, 0, connection_id, 0)); } if (message_ref->reply_to_message_ != nullptr) { drop_internal_reply_to_message_in_another_chat(message_ref->reply_to_message_); @@ -13590,7 +13665,7 @@ void Client::process_new_business_message_queue(const td::string &connection_id) queue.has_active_request_ = true; return send_request( make_object(reply_sticker_set_id), - td::make_unique(this, reply_sticker_set_id, 0, 0, connection_id)); + td::make_unique(this, reply_sticker_set_id, 0, 0, connection_id, 0)); } } @@ -13744,7 +13819,7 @@ void Client::init_message(MessageInfo *message_info, object_ptr auto sticker_set_id = get_sticker_set_id(message_info->content); if (!have_sticker_set_name(sticker_set_id)) { send_request(make_object(sticker_set_id), - td::make_unique(this, sticker_set_id, 0, 0, td::string())); + td::make_unique(this, sticker_set_id, 0, 0, td::string(), 0)); } } else if (message->content_->get_id() == td_api::messagePoll::ID) { message_info->content = std::move(message->content_); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 58b234e..d264203 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -257,7 +257,7 @@ class Client final : public WebhookActor::Callback { void on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, int64 new_message_chat_id, const td::string &new_message_business_connection_id, - object_ptr sticker_set); + int64 new_business_callback_query_user_id, object_ptr sticker_set); void on_get_sticker_set_name(int64 set_id, const td::string &name); @@ -1063,6 +1063,10 @@ class Client final : public WebhookActor::Callback { void process_new_callback_query_queue(int64 user_id, int state); + void add_new_business_callback_query(object_ptr &&query); + + void process_new_business_callback_query_queue(int64 user_id); + void add_new_inline_callback_query(object_ptr &&query); void add_new_shipping_query(object_ptr &&query); @@ -1240,6 +1244,12 @@ class Client final : public WebhookActor::Callback { }; td::FlatHashMap new_callback_query_queues_; // sender_user_id -> queue + struct NewBusinessCallbackQueryQueue { + std::queue> queue_; + bool has_active_request_ = false; + }; + td::FlatHashMap new_business_callback_query_queues_; // sender_user_id -> queue + td::WaitFreeHashMap sticker_set_names_; td::WaitFreeHashMap last_send_message_time_; From 7ee51f8c6de1038b5d6c53a698dd94ebbd697090 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 11 Jun 2024 22:27:25 +0300 Subject: [PATCH 115/162] Support editMessageText for business messages. --- telegram-bot-api/Client.cpp | 45 +++++++++++++++++++++++++++---------- telegram-bot-api/Client.h | 2 +- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index fd1a290..bd94386 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4129,9 +4129,9 @@ class Client::TdOnSendMessageCallback final : public TdQueryCallback { PromisedQueryPtr query_; }; -class Client::TdOnSendBusinessMessageCallback final : public TdQueryCallback { +class Client::TdOnReturnBusinessMessageCallback final : public TdQueryCallback { public: - TdOnSendBusinessMessageCallback(Client *client, td::string business_connection_id, PromisedQueryPtr query) + TdOnReturnBusinessMessageCallback(Client *client, td::string business_connection_id, PromisedQueryPtr query) : client_(client), business_connection_id_(std::move(business_connection_id)), query_(std::move(query)) { } @@ -4143,7 +4143,7 @@ class Client::TdOnSendBusinessMessageCallback final : public TdQueryCallback { CHECK(result->get_id() == td_api::businessMessage::ID); auto message = client_->create_business_message(std::move(business_connection_id_), move_object_as(result)); - answer_query(JsonMessage(message.get(), true, "sent business message", client_), std::move(query_)); + answer_query(JsonMessage(message.get(), true, "business message", client_), std::move(query_)); } private: @@ -10269,6 +10269,7 @@ td::Status Client::process_set_message_reaction_query(PromisedQueryPtr &query) { td::Status Client::process_edit_message_text_query(PromisedQueryPtr &query) { TRY_RESULT(input_message_text, get_input_message_text(query.get())); + auto business_connection_id = query->arg("business_connection_id"); auto chat_id = query->arg("chat_id"); auto message_id = get_message_id(query.get()); TRY_RESULT(reply_markup, get_reply_markup(query.get(), bot_user_ids_)); @@ -10286,10 +10287,30 @@ td::Status Client::process_edit_message_text_query(PromisedQueryPtr &query) { } else { resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, chat_id = chat_id.str(), message_id, input_message_text = std::move(input_message_text)]( - object_ptr reply_markup, PromisedQueryPtr query) mutable { + [this, business_connection_id = business_connection_id.str(), chat_id_str = chat_id.str(), message_id, + input_message_text = std::move(input_message_text)](object_ptr reply_markup, + PromisedQueryPtr query) mutable { + if (!business_connection_id.empty()) { + auto r_chat_id = get_business_connection_chat_id(chat_id_str); + if (r_chat_id.is_error()) { + return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); + } + auto chat_id = r_chat_id.move_as_ok(); + return check_business_connection( + business_connection_id, std::move(query), + [this, business_connection_id, chat_id, message_id, input_message_text = std::move(input_message_text), + reply_markup = std::move(reply_markup)](const BusinessConnection *business_connection, + PromisedQueryPtr query) mutable { + send_request(make_object(business_connection_id, chat_id, message_id, + std::move(reply_markup), + std::move(input_message_text)), + td::make_unique(this, business_connection_id, + std::move(query))); + }); + } + check_message( - chat_id, message_id, false, AccessRights::Edit, "message to edit", std::move(query), + chat_id_str, message_id, false, AccessRights::Edit, "message to edit", std::move(query), [this, input_message_text = std::move(input_message_text), reply_markup = std::move(reply_markup)]( int64 chat_id, int64 message_id, PromisedQueryPtr query) mutable { send_request(make_object(chat_id, message_id, std::move(reply_markup), @@ -12051,12 +12072,12 @@ void Client::do_send_message(object_ptr input_messa effect_id, reply_markup = std::move(reply_markup), input_message_content = std::move(input_message_content)](const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { - send_request( - make_object(business_connection->id_, chat_id, - get_input_message_reply_to(std::move(reply_parameters)), - disable_notification, protect_content, effect_id, - std::move(reply_markup), std::move(input_message_content)), - td::make_unique(this, business_connection->id_, std::move(query))); + send_request(make_object( + business_connection->id_, chat_id, + get_input_message_reply_to(std::move(reply_parameters)), disable_notification, + protect_content, effect_id, std::move(reply_markup), std::move(input_message_content)), + td::make_unique(this, business_connection->id_, + std::move(query))); }); } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index d264203..4a47f77 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -206,7 +206,7 @@ class Client final : public WebhookActor::Callback { class TdOnInitCallback; class TdOnGetUserProfilePhotosCallback; class TdOnSendMessageCallback; - class TdOnSendBusinessMessageCallback; + class TdOnReturnBusinessMessageCallback; class TdOnSendMessageAlbumCallback; class TdOnSendBusinessMessageAlbumCallback; class TdOnForwardMessagesCallback; From c8079841edd361f40d6bbe86f91739157a284299 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 11 Jun 2024 22:41:59 +0300 Subject: [PATCH 116/162] Support editMessageLiveLocation for business messages. --- telegram-bot-api/Client.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index bd94386..2bc4cc4 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -10330,6 +10330,7 @@ td::Status Client::process_edit_message_live_location_query(PromisedQueryPtr &qu if (query->method() == "editmessagelivelocation") { TRY_RESULT_ASSIGN(location, get_location(query.get())); } + auto business_connection_id = query->arg("business_connection_id"); auto chat_id = query->arg("chat_id"); auto message_id = get_message_id(query.get()); TRY_RESULT(reply_markup, get_reply_markup(query.get(), bot_user_ids_)); @@ -10348,9 +10349,29 @@ td::Status Client::process_edit_message_live_location_query(PromisedQueryPtr &qu } else { resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, chat_id = chat_id.str(), message_id, location = std::move(location), live_period, heading, + [this, business_connection_id = business_connection_id.str(), chat_id_str = chat_id.str(), message_id, + location = std::move(location), live_period, heading, proximity_alert_radius](object_ptr reply_markup, PromisedQueryPtr query) mutable { - check_message(chat_id, message_id, false, AccessRights::Edit, "message to edit", std::move(query), + if (!business_connection_id.empty()) { + auto r_chat_id = get_business_connection_chat_id(chat_id_str); + if (r_chat_id.is_error()) { + return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); + } + auto chat_id = r_chat_id.move_as_ok(); + return check_business_connection( + business_connection_id, std::move(query), + [this, business_connection_id, chat_id, message_id, location = std::move(location), live_period, + heading, proximity_alert_radius, reply_markup = std::move(reply_markup)]( + const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { + send_request(make_object( + business_connection_id, chat_id, message_id, std::move(reply_markup), + std::move(location), live_period, heading, proximity_alert_radius), + td::make_unique(this, business_connection_id, + std::move(query))); + }); + } + + check_message(chat_id_str, message_id, false, AccessRights::Edit, "message to edit", std::move(query), [this, location = std::move(location), live_period, heading, proximity_alert_radius, reply_markup = std::move(reply_markup)](int64 chat_id, int64 message_id, PromisedQueryPtr query) mutable { From 6c01c85d27655784991d0f9788a9a2c8ee39d0d1 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 11 Jun 2024 22:44:26 +0300 Subject: [PATCH 117/162] Support editMessageMedia for business messages. --- telegram-bot-api/Client.cpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 2bc4cc4..eebc7ba 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -10386,6 +10386,7 @@ td::Status Client::process_edit_message_live_location_query(PromisedQueryPtr &qu } td::Status Client::process_edit_message_media_query(PromisedQueryPtr &query) { + auto business_connection_id = query->arg("business_connection_id"); auto chat_id = query->arg("chat_id"); auto message_id = get_message_id(query.get()); TRY_RESULT(reply_markup, get_reply_markup(query.get(), bot_user_ids_)); @@ -10404,10 +10405,30 @@ td::Status Client::process_edit_message_media_query(PromisedQueryPtr &query) { } else { resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, chat_id = chat_id.str(), message_id, input_message_content = std::move(input_media)]( - object_ptr reply_markup, PromisedQueryPtr query) mutable { + [this, business_connection_id = business_connection_id.str(), chat_id_str = chat_id.str(), message_id, + input_message_content = std::move(input_media)](object_ptr reply_markup, + PromisedQueryPtr query) mutable { + if (!business_connection_id.empty()) { + auto r_chat_id = get_business_connection_chat_id(chat_id_str); + if (r_chat_id.is_error()) { + return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); + } + auto chat_id = r_chat_id.move_as_ok(); + return check_business_connection( + business_connection_id, std::move(query), + [this, business_connection_id, chat_id, message_id, + input_message_content = std::move(input_message_content), reply_markup = std::move(reply_markup)]( + const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { + send_request(make_object(business_connection_id, chat_id, + message_id, std::move(reply_markup), + std::move(input_message_content)), + td::make_unique(this, business_connection_id, + std::move(query))); + }); + } + check_message( - chat_id, message_id, false, AccessRights::Edit, "message to edit", std::move(query), + chat_id_str, message_id, false, AccessRights::Edit, "message to edit", std::move(query), [this, reply_markup = std::move(reply_markup), input_message_content = std::move(input_message_content)]( int64 chat_id, int64 message_id, PromisedQueryPtr query) mutable { send_request(make_object(chat_id, message_id, std::move(reply_markup), From f75e2155c175ce7807a317f455b5efd6531f5503 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 11 Jun 2024 22:50:39 +0300 Subject: [PATCH 118/162] Support editMessageCaption for business messages. --- telegram-bot-api/Client.cpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index eebc7ba..23414cb 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -10441,6 +10441,7 @@ td::Status Client::process_edit_message_media_query(PromisedQueryPtr &query) { } td::Status Client::process_edit_message_caption_query(PromisedQueryPtr &query) { + auto business_connection_id = query->arg("business_connection_id"); auto chat_id = query->arg("chat_id"); auto message_id = get_message_id(query.get()); TRY_RESULT(reply_markup, get_reply_markup(query.get(), bot_user_ids_)); @@ -10460,9 +10461,29 @@ td::Status Client::process_edit_message_caption_query(PromisedQueryPtr &query) { } else { resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, chat_id = chat_id.str(), message_id, caption = std::move(caption), show_caption_above_media]( - object_ptr reply_markup, PromisedQueryPtr query) mutable { - check_message(chat_id, message_id, false, AccessRights::Edit, "message to edit", std::move(query), + [this, business_connection_id = business_connection_id.str(), chat_id_str = chat_id.str(), message_id, + caption = std::move(caption), + show_caption_above_media](object_ptr reply_markup, PromisedQueryPtr query) mutable { + if (!business_connection_id.empty()) { + auto r_chat_id = get_business_connection_chat_id(chat_id_str); + if (r_chat_id.is_error()) { + return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); + } + auto chat_id = r_chat_id.move_as_ok(); + return check_business_connection( + business_connection_id, std::move(query), + [this, business_connection_id, chat_id, message_id, reply_markup = std::move(reply_markup), + caption = std::move(caption), show_caption_above_media](const BusinessConnection *business_connection, + PromisedQueryPtr query) mutable { + send_request(make_object( + business_connection_id, chat_id, message_id, std::move(reply_markup), + std::move(caption), show_caption_above_media), + td::make_unique(this, business_connection_id, + std::move(query))); + }); + } + + check_message(chat_id_str, message_id, false, AccessRights::Edit, "message to edit", std::move(query), [this, reply_markup = std::move(reply_markup), caption = std::move(caption), show_caption_above_media](int64 chat_id, int64 message_id, PromisedQueryPtr query) mutable { send_request( From 86fb9bc8b8fdda6758a1d0ee1114da938ee79a52 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 11 Jun 2024 22:53:41 +0300 Subject: [PATCH 119/162] Support editMessageReplyMarkup for business messages. --- telegram-bot-api/Client.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 23414cb..b77592c 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -10497,6 +10497,7 @@ td::Status Client::process_edit_message_caption_query(PromisedQueryPtr &query) { } td::Status Client::process_edit_message_reply_markup_query(PromisedQueryPtr &query) { + auto business_connection_id = query->arg("business_connection_id"); auto chat_id = query->arg("chat_id"); auto message_id = get_message_id(query.get()); TRY_RESULT(reply_markup, get_reply_markup(query.get(), bot_user_ids_)); @@ -10513,9 +10514,26 @@ td::Status Client::process_edit_message_reply_markup_query(PromisedQueryPtr &que } else { resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, chat_id = chat_id.str(), message_id](object_ptr reply_markup, - PromisedQueryPtr query) { - check_message(chat_id, message_id, false, AccessRights::Edit, "message to edit", std::move(query), + [this, business_connection_id = business_connection_id.str(), chat_id_str = chat_id.str(), message_id]( + object_ptr reply_markup, PromisedQueryPtr query) { + if (!business_connection_id.empty()) { + auto r_chat_id = get_business_connection_chat_id(chat_id_str); + if (r_chat_id.is_error()) { + return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); + } + auto chat_id = r_chat_id.move_as_ok(); + return check_business_connection( + business_connection_id, std::move(query), + [this, business_connection_id, chat_id, message_id, reply_markup = std::move(reply_markup)]( + const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { + send_request(make_object(business_connection_id, chat_id, + message_id, std::move(reply_markup)), + td::make_unique(this, business_connection_id, + std::move(query))); + }); + } + + check_message(chat_id_str, message_id, false, AccessRights::Edit, "message to edit", std::move(query), [this, reply_markup = std::move(reply_markup)](int64 chat_id, int64 message_id, PromisedQueryPtr query) mutable { send_request( From bd31c2a9ce5154523d7afc89bce2c943592cc448 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 11 Jun 2024 23:02:03 +0300 Subject: [PATCH 120/162] Support stopPoll for business messages. --- telegram-bot-api/Client.cpp | 52 ++++++++++++++++++++++++++++++++++--- telegram-bot-api/Client.h | 1 + 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index b77592c..41562d4 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4359,6 +4359,34 @@ class Client::TdOnStopPollCallback final : public TdQueryCallback { PromisedQueryPtr query_; }; +class Client::TdOnStopBusinessPollCallback final : public TdQueryCallback { + public: + TdOnStopBusinessPollCallback(Client *client, const td::string &business_connection_id, PromisedQueryPtr query) + : client_(client), business_connection_id_(business_connection_id), 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::businessMessage::ID); + auto message = client_->create_business_message(std::move(business_connection_id_), + move_object_as(result)); + if (message->content->get_id() != td_api::messagePoll::ID) { + LOG(ERROR) << "Poll not found in a business message from connection " << business_connection_id_; + return fail_query_with_error(std::move(query_), 400, "message poll not found"); + } + auto message_poll = static_cast(message->content.get()); + answer_query(JsonPoll(message_poll->poll_.get(), client_), std::move(query_)); + } + + private: + Client *client_; + td::string business_connection_id_; + PromisedQueryPtr query_; +}; + class Client::TdOnOkQueryCallback final : public TdQueryCallback { public: explicit TdOnOkQueryCallback(PromisedQueryPtr query) : query_(std::move(query)) { @@ -10021,15 +10049,33 @@ td::Status Client::process_send_poll_query(PromisedQueryPtr &query) { } td::Status Client::process_stop_poll_query(PromisedQueryPtr &query) { + auto business_connection_id = query->arg("business_connection_id"); auto chat_id = query->arg("chat_id"); auto message_id = get_message_id(query.get()); TRY_RESULT(reply_markup, get_reply_markup(query.get(), bot_user_ids_)); resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, chat_id = chat_id.str(), message_id](object_ptr reply_markup, - PromisedQueryPtr query) { - check_message(chat_id, message_id, false, AccessRights::Edit, "message with poll to stop", std::move(query), + [this, business_connection_id = business_connection_id.str(), chat_id_str = chat_id.str(), message_id]( + object_ptr reply_markup, PromisedQueryPtr query) { + if (!business_connection_id.empty()) { + auto r_chat_id = get_business_connection_chat_id(chat_id_str); + if (r_chat_id.is_error()) { + return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); + } + auto chat_id = r_chat_id.move_as_ok(); + return check_business_connection( + business_connection_id, std::move(query), + [this, business_connection_id, chat_id, message_id, reply_markup = std::move(reply_markup)]( + const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { + send_request( + make_object(business_connection_id, chat_id, message_id, + std::move(reply_markup)), + td::make_unique(this, business_connection_id, std::move(query))); + }); + } + + check_message(chat_id_str, message_id, false, AccessRights::Edit, "message with poll to stop", std::move(query), [this, reply_markup = std::move(reply_markup)](int64 chat_id, int64 message_id, PromisedQueryPtr query) mutable { send_request( diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 4a47f77..3d53307 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -214,6 +214,7 @@ class Client final : public WebhookActor::Callback { class TdOnEditMessageCallback; class TdOnEditInlineMessageCallback; class TdOnStopPollCallback; + class TdOnStopBusinessPollCallback; class TdOnOkQueryCallback; class TdOnGetReplyMessageCallback; class TdOnGetEditedMessageCallback; From a879acc49df6bbd61c5a06d09f0c488031e540a5 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 11 Jun 2024 23:12:04 +0300 Subject: [PATCH 121/162] Add check_business_connection_chat_id. --- telegram-bot-api/Client.cpp | 140 +++++++++++++++--------------------- telegram-bot-api/Client.h | 4 ++ 2 files changed, 60 insertions(+), 84 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 41562d4..b39f3e6 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -6074,6 +6074,21 @@ void Client::check_business_connection(const td::string &business_connection_id, td::make_unique>(this, std::move(query), std::move(on_success))); } +template +void Client::check_business_connection_chat_id(const td::string &business_connection_id, const td::string &chat_id_str, + PromisedQueryPtr query, OnSuccess on_success) { + auto r_chat_id = get_business_connection_chat_id(chat_id_str); + if (r_chat_id.is_error()) { + return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); + } + auto chat_id = r_chat_id.move_as_ok(); + check_business_connection(business_connection_id, std::move(query), + [this, chat_id, on_success = std::move(on_success)]( + const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { + on_success(business_connection, chat_id, std::move(query)); + }); +} + template void Client::check_bot_command_scope(BotCommandScope &&scope, PromisedQueryPtr query, OnSuccess on_success) { CHECK(scope.scope_ != nullptr); @@ -10059,15 +10074,10 @@ td::Status Client::process_stop_poll_query(PromisedQueryPtr &query) { [this, business_connection_id = business_connection_id.str(), chat_id_str = chat_id.str(), message_id]( object_ptr reply_markup, PromisedQueryPtr query) { if (!business_connection_id.empty()) { - auto r_chat_id = get_business_connection_chat_id(chat_id_str); - if (r_chat_id.is_error()) { - return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); - } - auto chat_id = r_chat_id.move_as_ok(); - return check_business_connection( - business_connection_id, std::move(query), - [this, business_connection_id, chat_id, message_id, reply_markup = std::move(reply_markup)]( - const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { + return check_business_connection_chat_id( + business_connection_id, chat_id_str, std::move(query), + [this, business_connection_id, message_id, reply_markup = std::move(reply_markup)]( + const BusinessConnection *business_connection, int64 chat_id, PromisedQueryPtr query) mutable { send_request( make_object(business_connection_id, chat_id, message_id, std::move(reply_markup)), @@ -10224,17 +10234,11 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { input_message_contents = std::move(input_message_contents)](object_ptr reply_markup, PromisedQueryPtr query) mutable { if (!business_connection_id.empty()) { - auto r_chat_id = get_business_connection_chat_id(chat_id_str); - if (r_chat_id.is_error()) { - return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); - } - auto chat_id = r_chat_id.move_as_ok(); - return check_business_connection( - business_connection_id, std::move(query), - [this, chat_id, reply_parameters = std::move(reply_parameters), disable_notification, protect_content, - effect_id, input_message_contents = std::move(input_message_contents), - reply_markup = std::move(reply_markup)](const BusinessConnection *business_connection, - PromisedQueryPtr query) mutable { + return check_business_connection_chat_id( + business_connection_id, chat_id_str, std::move(query), + [this, reply_parameters = std::move(reply_parameters), disable_notification, protect_content, effect_id, + input_message_contents = std::move(input_message_contents), reply_markup = std::move(reply_markup)]( + const BusinessConnection *business_connection, int64 chat_id, PromisedQueryPtr query) mutable { send_request( make_object( business_connection->id_, chat_id, get_input_message_reply_to(std::move(reply_parameters)), @@ -10277,11 +10281,10 @@ td::Status Client::process_send_chat_action_query(PromisedQueryPtr &query) { return td::Status::Error(400, "Wrong parameter action in request"); } if (!business_connection_id.empty()) { - TRY_RESULT(chat_id, get_business_connection_chat_id(chat_id_str)); - check_business_connection( - business_connection_id, std::move(query), - [this, chat_id, action = std::move(action)](const BusinessConnection *business_connection, - PromisedQueryPtr query) mutable { + check_business_connection_chat_id( + business_connection_id, chat_id_str.str(), std::move(query), + [this, action = std::move(action)](const BusinessConnection *business_connection, int64 chat_id, + PromisedQueryPtr query) mutable { send_request(make_object(chat_id, 0, business_connection->id_, std::move(action)), td::make_unique(std::move(query))); }); @@ -10337,15 +10340,10 @@ td::Status Client::process_edit_message_text_query(PromisedQueryPtr &query) { input_message_text = std::move(input_message_text)](object_ptr reply_markup, PromisedQueryPtr query) mutable { if (!business_connection_id.empty()) { - auto r_chat_id = get_business_connection_chat_id(chat_id_str); - if (r_chat_id.is_error()) { - return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); - } - auto chat_id = r_chat_id.move_as_ok(); - return check_business_connection( - business_connection_id, std::move(query), - [this, business_connection_id, chat_id, message_id, input_message_text = std::move(input_message_text), - reply_markup = std::move(reply_markup)](const BusinessConnection *business_connection, + return check_business_connection_chat_id( + business_connection_id, chat_id_str, std::move(query), + [this, business_connection_id, message_id, input_message_text = std::move(input_message_text), + reply_markup = std::move(reply_markup)](const BusinessConnection *business_connection, int64 chat_id, PromisedQueryPtr query) mutable { send_request(make_object(business_connection_id, chat_id, message_id, std::move(reply_markup), @@ -10399,16 +10397,11 @@ td::Status Client::process_edit_message_live_location_query(PromisedQueryPtr &qu location = std::move(location), live_period, heading, proximity_alert_radius](object_ptr reply_markup, PromisedQueryPtr query) mutable { if (!business_connection_id.empty()) { - auto r_chat_id = get_business_connection_chat_id(chat_id_str); - if (r_chat_id.is_error()) { - return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); - } - auto chat_id = r_chat_id.move_as_ok(); - return check_business_connection( - business_connection_id, std::move(query), - [this, business_connection_id, chat_id, message_id, location = std::move(location), live_period, - heading, proximity_alert_radius, reply_markup = std::move(reply_markup)]( - const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { + return check_business_connection_chat_id( + business_connection_id, chat_id_str, std::move(query), + [this, business_connection_id, message_id, location = std::move(location), live_period, heading, + proximity_alert_radius, reply_markup = std::move(reply_markup)]( + const BusinessConnection *business_connection, int64 chat_id, PromisedQueryPtr query) mutable { send_request(make_object( business_connection_id, chat_id, message_id, std::move(reply_markup), std::move(location), live_period, heading, proximity_alert_radius), @@ -10455,16 +10448,11 @@ td::Status Client::process_edit_message_media_query(PromisedQueryPtr &query) { input_message_content = std::move(input_media)](object_ptr reply_markup, PromisedQueryPtr query) mutable { if (!business_connection_id.empty()) { - auto r_chat_id = get_business_connection_chat_id(chat_id_str); - if (r_chat_id.is_error()) { - return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); - } - auto chat_id = r_chat_id.move_as_ok(); - return check_business_connection( - business_connection_id, std::move(query), - [this, business_connection_id, chat_id, message_id, - input_message_content = std::move(input_message_content), reply_markup = std::move(reply_markup)]( - const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { + return check_business_connection_chat_id( + business_connection_id, chat_id_str, std::move(query), + [this, business_connection_id, message_id, input_message_content = std::move(input_message_content), + reply_markup = std::move(reply_markup)](const BusinessConnection *business_connection, int64 chat_id, + PromisedQueryPtr query) mutable { send_request(make_object(business_connection_id, chat_id, message_id, std::move(reply_markup), std::move(input_message_content)), @@ -10511,16 +10499,11 @@ td::Status Client::process_edit_message_caption_query(PromisedQueryPtr &query) { caption = std::move(caption), show_caption_above_media](object_ptr reply_markup, PromisedQueryPtr query) mutable { if (!business_connection_id.empty()) { - auto r_chat_id = get_business_connection_chat_id(chat_id_str); - if (r_chat_id.is_error()) { - return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); - } - auto chat_id = r_chat_id.move_as_ok(); - return check_business_connection( - business_connection_id, std::move(query), - [this, business_connection_id, chat_id, message_id, reply_markup = std::move(reply_markup), - caption = std::move(caption), show_caption_above_media](const BusinessConnection *business_connection, - PromisedQueryPtr query) mutable { + return check_business_connection_chat_id( + business_connection_id, chat_id_str, std::move(query), + [this, business_connection_id, message_id, reply_markup = std::move(reply_markup), + caption = std::move(caption), show_caption_above_media]( + const BusinessConnection *business_connection, int64 chat_id, PromisedQueryPtr query) mutable { send_request(make_object( business_connection_id, chat_id, message_id, std::move(reply_markup), std::move(caption), show_caption_above_media), @@ -10563,15 +10546,10 @@ td::Status Client::process_edit_message_reply_markup_query(PromisedQueryPtr &que [this, business_connection_id = business_connection_id.str(), chat_id_str = chat_id.str(), message_id]( object_ptr reply_markup, PromisedQueryPtr query) { if (!business_connection_id.empty()) { - auto r_chat_id = get_business_connection_chat_id(chat_id_str); - if (r_chat_id.is_error()) { - return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); - } - auto chat_id = r_chat_id.move_as_ok(); - return check_business_connection( - business_connection_id, std::move(query), - [this, business_connection_id, chat_id, message_id, reply_markup = std::move(reply_markup)]( - const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { + return check_business_connection_chat_id( + business_connection_id, chat_id_str, std::move(query), + [this, business_connection_id, message_id, reply_markup = std::move(reply_markup)]( + const BusinessConnection *business_connection, int64 chat_id, PromisedQueryPtr query) mutable { send_request(make_object(business_connection_id, chat_id, message_id, std::move(reply_markup)), td::make_unique(this, business_connection_id, @@ -12188,17 +12166,11 @@ void Client::do_send_message(object_ptr input_messa input_message_content = std::move(input_message_content)](object_ptr reply_markup, PromisedQueryPtr query) mutable { if (!business_connection_id.empty()) { - auto r_chat_id = get_business_connection_chat_id(chat_id_str); - if (r_chat_id.is_error()) { - return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); - } - auto chat_id = r_chat_id.move_as_ok(); - return check_business_connection( - business_connection_id, std::move(query), - [this, chat_id, reply_parameters = std::move(reply_parameters), disable_notification, protect_content, - effect_id, reply_markup = std::move(reply_markup), - input_message_content = std::move(input_message_content)](const BusinessConnection *business_connection, - PromisedQueryPtr query) mutable { + return check_business_connection_chat_id( + business_connection_id, chat_id_str, std::move(query), + [this, reply_parameters = std::move(reply_parameters), disable_notification, protect_content, effect_id, + reply_markup = std::move(reply_markup), input_message_content = std::move(input_message_content)]( + const BusinessConnection *business_connection, int64 chat_id, PromisedQueryPtr query) mutable { send_request(make_object( business_connection->id_, chat_id, get_input_message_reply_to(std::move(reply_parameters)), disable_notification, diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 3d53307..669a395 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -344,6 +344,10 @@ class Client final : public WebhookActor::Callback { void check_business_connection(const td::string &business_connection_id, PromisedQueryPtr query, OnSuccess on_success); + template + void check_business_connection_chat_id(const td::string &business_connection_id, const td::string &chat_id_str, + PromisedQueryPtr query, OnSuccess on_success); + template void check_bot_command_scope(BotCommandScope &&scope, PromisedQueryPtr query, OnSuccess on_success); From 025884aeca08f09486763afcb37b52a99ca1cda7 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 15 Jun 2024 00:57:27 +0300 Subject: [PATCH 122/162] Add getStarTransactions. --- telegram-bot-api/Client.cpp | 146 +++++++++++++++++++++++++++++++++++- telegram-bot-api/Client.h | 6 ++ 2 files changed, 150 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index b39f3e6..3444998 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -246,6 +246,7 @@ bool Client::init_methods() { 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("getstartransactions", &Client::process_get_star_transactions_query); methods_.emplace("refundstarpayment", &Client::process_refund_star_payment_query); methods_.emplace("setgamescore", &Client::process_set_game_score_query); methods_.emplace("getgamehighscores", &Client::process_get_game_high_scores_query); @@ -3928,6 +3929,117 @@ class Client::JsonBusinessMessagesDeleted final : public td::Jsonable { const Client *client_; }; +class Client::JsonRevenueWithdrawalState final : public td::Jsonable { + public: + explicit JsonRevenueWithdrawalState(const td_api::RevenueWithdrawalState *state) : state_(state) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + switch (state_->get_id()) { + case td_api::revenueWithdrawalStatePending::ID: + object("type", "pending"); + break; + case td_api::revenueWithdrawalStateSucceeded::ID: { + auto state = static_cast(state_); + object("type", "succeeded"); + object("date", state->date_); + object("url", state->url_); + break; + } + case td_api::revenueWithdrawalStateFailed::ID: + object("type", "failed"); + break; + default: + UNREACHABLE(); + } + } + + private: + const td_api::RevenueWithdrawalState *state_; +}; + +class Client::JsonStarTransactionPartner final : public td::Jsonable { + public: + JsonStarTransactionPartner(const td_api::StarTransactionPartner *source, const Client *client) + : source_(source), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + switch (source_->get_id()) { + case td_api::starTransactionPartnerFragment::ID: { + auto source_fragment = static_cast(source_); + object("type", "fragment"); + if (source_fragment->withdrawal_state_ != nullptr) { + object("withdrawal_state", JsonRevenueWithdrawalState(source_fragment->withdrawal_state_.get())); + } + break; + } + case td_api::starTransactionPartnerUser::ID: { + auto source_user = static_cast(source_); + object("type", "user"); + object("user", JsonUser(source_user->user_id_, client_)); + break; + } + case td_api::starTransactionPartnerTelegram::ID: + case td_api::starTransactionPartnerAppStore::ID: + case td_api::starTransactionPartnerGooglePlay::ID: + case td_api::starTransactionPartnerChannel::ID: + LOG(ERROR) << "Receive " << to_string(*source_); + object("type", "other"); + break; + case td_api::starTransactionPartnerUnsupported::ID: + object("type", "other"); + break; + default: + UNREACHABLE(); + } + } + + private: + const td_api::StarTransactionPartner *source_; + const Client *client_; +}; + +class Client::JsonStarTransaction final : public td::Jsonable { + public: + JsonStarTransaction(const td_api::starTransaction *transaction, const Client *client) + : transaction_(transaction), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("id", transaction_->id_); + object("date", transaction_->date_); + if (transaction_->star_count_ > 0) { + object("amount", transaction_->star_count_); + object("source", JsonStarTransactionPartner(transaction_->partner_.get(), client_)); + } else { + object("amount", -transaction_->star_count_); + object("receiver", JsonStarTransactionPartner(transaction_->partner_.get(), client_)); + } + } + + private: + const td_api::starTransaction *transaction_; + const Client *client_; +}; + +class Client::JsonStarTransactions final : public td::Jsonable { + public: + JsonStarTransactions(const td_api::starTransactions *transactions, const Client *client) + : transactions_(transactions), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("transactions", td::json_array(transactions_->transactions_, [client = client_](const auto &transaction) { + return JsonStarTransaction(transaction.get(), client); + })); + } + + private: + const td_api::starTransactions *transactions_; + const Client *client_; +}; + class Client::JsonUpdateTypes final : public td::Jsonable { public: explicit JsonUpdateTypes(td::uint32 update_types) : update_types_(update_types) { @@ -5388,12 +5500,12 @@ class Client::TdOnGetChatInviteLinkCallback final : public TdQueryCallback { if (result->get_id() == td_api::chatInviteLink::ID) { auto invite_link = move_object_as(result); - return answer_query(JsonChatInviteLink(invite_link.get(), client_), std::move(query_)); + answer_query(JsonChatInviteLink(invite_link.get(), client_), std::move(query_)); } else { CHECK(result->get_id() == td_api::chatInviteLinks::ID); auto invite_links = move_object_as(result); CHECK(!invite_links->invite_links_.empty()); - return answer_query(JsonChatInviteLink(invite_links->invite_links_[0].get(), client_), std::move(query_)); + answer_query(JsonChatInviteLink(invite_links->invite_links_[0].get(), client_), std::move(query_)); } } @@ -5402,6 +5514,27 @@ class Client::TdOnGetChatInviteLinkCallback final : public TdQueryCallback { PromisedQueryPtr query_; }; +class Client::TdOnGetStarTransactionsQueryCallback final : public TdQueryCallback { + public: + TdOnGetStarTransactionsQueryCallback(const 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::starTransactions::ID); + auto transactions = move_object_as(result); + answer_query(JsonStarTransactions(transactions.get(), client_), std::move(query_)); + } + + private: + const Client *client_; + PromisedQueryPtr query_; +}; + class Client::TdOnGetGameHighScoresCallback final : public TdQueryCallback { public: TdOnGetGameHighScoresCallback(const Client *client, PromisedQueryPtr query) @@ -10610,6 +10743,15 @@ td::Status Client::process_create_invoice_link_query(PromisedQueryPtr &query) { return td::Status::OK(); } +td::Status Client::process_get_star_transactions_query(PromisedQueryPtr &query) { + auto offset = get_integer_arg(query.get(), "offset", 0, 0); + auto limit = get_integer_arg(query.get(), "limit", 100, 1, 100); + send_request(make_object(make_object(my_id_), nullptr, + td::to_string(offset), limit), + td::make_unique(this, std::move(query))); + return td::Status::OK(); +} + td::Status Client::process_refund_star_payment_query(PromisedQueryPtr &query) { TRY_RESULT(user_id, get_user_id(query.get())); TRY_RESULT(telegram_payment_charge_id, get_required_string_arg(query.get(), "telegram_payment_charge_id")); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 669a395..87964a7 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -195,6 +195,10 @@ class Client final : public WebhookActor::Callback { class JsonGiveawayWinners; class JsonGiveawayCompleted; class JsonChatBoostAdded; + class JsonRevenueWithdrawalState; + class JsonStarTransactionPartner; + class JsonStarTransaction; + class JsonStarTransactions; class JsonUpdateTypes; class JsonWebhookInfo; class JsonStickerSet; @@ -238,6 +242,7 @@ class Client final : public WebhookActor::Callback { class TdOnGetSupergroupMemberCountCallback; class TdOnGetUserChatBoostsCallback; class TdOnCreateInvoiceLinkCallback; + class TdOnGetStarTransactionsQueryCallback; class TdOnReplacePrimaryChatInviteLinkCallback; class TdOnGetChatInviteLinkCallback; class TdOnGetGameHighScoresCallback; @@ -652,6 +657,7 @@ class Client final : public WebhookActor::Callback { 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_get_star_transactions_query(PromisedQueryPtr &query); td::Status process_refund_star_payment_query(PromisedQueryPtr &query); td::Status process_set_game_score_query(PromisedQueryPtr &query); td::Status process_get_game_high_scores_query(PromisedQueryPtr &query); From ecfce9042b61bc3719f51014aff238b5ac14a5ad Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 18 Jun 2024 01:01:31 +0300 Subject: [PATCH 123/162] Update version to 7.5. --- 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 b7b9380..8d38880 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 7.4 LANGUAGES CXX) +project(TelegramBotApi VERSION 7.5 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 6bc71fb..a5af3f6 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.4"; + parameters->version_ = "7.5"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats(); From 1873bf58f3aa8eabdf09ab2f664a55e22bf495f6 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 26 Jun 2024 00:46:00 +0300 Subject: [PATCH 124/162] Simplify some calls to fail_query_with_error. --- telegram-bot-api/Client.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 3444998..4ed5580 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4865,7 +4865,7 @@ class Client::TdOnGetChatMemberCallback final : public TdQueryCallback { 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), "user not found"); + return fail_query_with_error(std::move(query_), move_object_as(result)); } CHECK(result->get_id() == td_api::chatMember::ID); @@ -5197,7 +5197,7 @@ class Client::TdOnGetChatPinnedMessageToUnpinCallback final : public TdQueryCall if (error->code_ == 429) { return fail_query_with_error(std::move(query_), std::move(error)); } else { - return fail_query_with_error(std::move(query_), make_object(400, "Message to unpin not found")); + return fail_query_with_error(std::move(query_), 400, "Message to unpin not found"); } } @@ -5252,8 +5252,7 @@ class Client::TdOnGetMyDefaultAdministratorRightsCallback final : public TdQuery auto full_info = move_object_as(result); if (full_info->bot_info_ == nullptr) { LOG(ERROR) << "Have no bot info for self"; - return fail_query_with_error(std::move(query_), - make_object(500, "Requested data is inaccessible")); + return fail_query_with_error(std::move(query_), 500, "Requested data is inaccessible"); } auto bot_info = std::move(full_info->bot_info_); const auto *rights = for_channels_ ? bot_info->default_channel_administrator_rights_.get() From f47e0a9fde27343dea9e1a80e87f898acaa803ff Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 30 Jun 2024 12:43:03 +0300 Subject: [PATCH 125/162] Update TDLib to 1.8.32. --- td | 2 +- telegram-bot-api/Client.cpp | 94 ++++++++++++++++++++++++++++++++----- telegram-bot-api/Client.h | 5 ++ 3 files changed, 89 insertions(+), 12 deletions(-) diff --git a/td b/td index 8f19c75..35cfcf5 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 8f19c751dc296cedb9a921badb7a02a8c0cb1aeb +Subproject commit 35cfcf5d15981b99e8f31a2195641f035dd516c3 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 4ed5580..c26a74d 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3177,6 +3177,8 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("boost_added", JsonChatBoostAdded(content)); break; } + case td_api::messagePaidMedia::ID: + break; default: UNREACHABLE(); } @@ -3974,10 +3976,10 @@ class Client::JsonStarTransactionPartner final : public td::Jsonable { } break; } - case td_api::starTransactionPartnerUser::ID: { - auto source_user = static_cast(source_); + case td_api::starTransactionPartnerBot::ID: { + auto source_user = static_cast(source_); object("type", "user"); - object("user", JsonUser(source_user->user_id_, client_)); + object("user", JsonUser(source_user->bot_user_id_, client_)); break; } case td_api::starTransactionPartnerTelegram::ID: @@ -3987,6 +3989,7 @@ class Client::JsonStarTransactionPartner final : public td::Jsonable { LOG(ERROR) << "Receive " << to_string(*source_); object("type", "other"); break; + case td_api::starTransactionPartnerTelegramAds::ID: case td_api::starTransactionPartnerUnsupported::ID: object("type", "other"); break; @@ -7915,7 +7918,7 @@ td::Result> Client::get_input_me need_email_address, need_shipping_address, send_phone_number_to_provider, send_email_address_to_provider, is_flexible), title, description, photo_url, photo_size, photo_width, photo_height, payload, provider_token, provider_data, - td::string(), nullptr); + td::string(), nullptr, nullptr); } if (is_input_message_content_required) { @@ -9318,10 +9321,10 @@ td::Result> Client::get_input_me td::vector(), duration, width, height, supports_streaming, std::move(caption), show_caption_above_media, nullptr, has_spoiler); } - if (for_album && type == "animation") { - return td::Status::Error(PSLICE() << "type \"" << type << "\" can't be used in sendMediaGroup"); - } if (type == "animation") { + if (for_album) { + return td::Status::Error(PSLICE() << "type \"" << type << "\" can't be used in sendMediaGroup"); + } TRY_RESULT(width, object.get_optional_int_field("width")); TRY_RESULT(height, object.get_optional_int_field("height")); TRY_RESULT(duration, object.get_optional_int_field("duration")); @@ -9399,6 +9402,67 @@ td::Result>> Client:: return std::move(contents); } +td::Result> Client::get_input_paid_media(const Query *query, + td::JsonValue &&input_media) const { + if (input_media.type() != td::JsonValue::Type::Object) { + return td::Status::Error("expected an Object"); + } + + auto &object = input_media.get_object(); + TRY_RESULT(media, object.get_optional_string_field("media")); + + auto input_file = get_input_file(query, td::Slice(), media, false); + if (input_file == nullptr) { + return td::Status::Error("media not found"); + } + + object_ptr input_thumbnail; + TRY_RESULT(thumbnail, object.get_optional_string_field("thumbnail")); + auto thumbnail_input_file = get_input_file(query, "thumbnail", thumbnail, true); + if (thumbnail_input_file != nullptr) { + input_thumbnail = make_object(std::move(thumbnail_input_file), 0, 0); + } + + TRY_RESULT(width, object.get_optional_int_field("width")); + TRY_RESULT(height, object.get_optional_int_field("height")); + width = td::clamp(width, 0, MAX_LENGTH); + height = td::clamp(height, 0, MAX_LENGTH); + + object_ptr media_type; + TRY_RESULT(type, object.get_required_string_field("type")); + if (type == "photo") { + media_type = make_object(); + } else if (type == "video") { + TRY_RESULT(duration, object.get_optional_int_field("duration")); + TRY_RESULT(supports_streaming, object.get_optional_bool_field("supports_streaming")); + duration = td::clamp(duration, 0, MAX_DURATION); + media_type = make_object(duration, supports_streaming); + } else { + return td::Status::Error(PSLICE() << "type \"" << type << "\" is unsupported"); + } + + return make_object(std::move(media_type), std::move(input_file), std::move(input_thumbnail), + td::vector(), width, height); +} + +td::Result> Client::get_input_paid_media(const Query *query, + td::Slice field_name) const { + TRY_RESULT(media, get_required_string_arg(query, field_name)); + + LOG(INFO) << "Parsing JSON object: " << media; + auto r_value = json_decode(media); + if (r_value.is_error()) { + LOG(INFO) << "Can't parse JSON object: " << r_value.error(); + return td::Status::Error(400, "Can't parse input paid media JSON object"); + } + + auto r_input_paid_media = get_input_paid_media(query, r_value.move_as_ok()); + if (r_input_paid_media.is_error()) { + return td::Status::Error(400, PSLICE() << "Can't parse InputPaidMedia: " << r_input_paid_media.error().message()); + } + return r_input_paid_media.move_as_ok(); +} + td::Result> Client::get_input_message_invoice( const Query *query) const { TRY_RESULT(title, get_required_string_arg(query, "title")); @@ -9456,10 +9520,15 @@ td::Result> Client::get_input_me auto send_email_address_to_provider = to_bool(query->arg("send_email_to_provider")); auto is_flexible = to_bool(query->arg("is_flexible")); - object_ptr extended_media; - if (!query->arg("extended_media").empty()) { - TRY_RESULT_ASSIGN(extended_media, get_input_media(query, "extended_media")); + object_ptr paid_media; + if (!query->arg("paid_media").empty()) { + TRY_RESULT_ASSIGN(paid_media, get_input_paid_media(query, "paid_media")); + } else if (!query->arg("extended_media").empty()) { + TRY_RESULT_ASSIGN(paid_media, get_input_paid_media(query, "extended_media")); } + TRY_RESULT(paid_media_caption, get_formatted_text(query->arg("paid_media_caption").str(), + query->arg("paid_media_caption_parse_mode").str(), + get_input_entities(query, "paid_media_caption_entities"))); return make_object( make_object(currency.str(), std::move(prices), max_tip_amount, std::move(suggested_tip_amounts), @@ -9467,7 +9536,8 @@ td::Result> Client::get_input_me need_shipping_address, send_phone_number_to_provider, send_email_address_to_provider, is_flexible), title.str(), description.str(), photo_url.str(), photo_size, photo_width, photo_height, payload.str(), - provider_token.str(), provider_data.str(), start_parameter.str(), std::move(extended_media)); + provider_token.str(), provider_data.str(), start_parameter.str(), std::move(paid_media), + std::move(paid_media_caption)); } td::Result>> Client::get_poll_options(const Query *query) { @@ -13548,6 +13618,8 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr>> get_input_message_contents( const Query *query, td::JsonValue &&value) const; + td::Result> get_input_paid_media(const Query *query, + td::JsonValue &&input_media) const; + + td::Result> get_input_paid_media(const Query *query, td::Slice field_name) const; + td::Result> get_input_message_invoice(const Query *query) const; static object_ptr get_message_send_options(bool disable_notification, From 76006f4a2e0a8afb58c0747a28d2849e4ce714ac Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 30 Jun 2024 13:26:14 +0300 Subject: [PATCH 126/162] Add "telegram_ads" transaction partner. --- 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 c26a74d..b48311a 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3982,6 +3982,9 @@ class Client::JsonStarTransactionPartner final : public td::Jsonable { object("user", JsonUser(source_user->bot_user_id_, client_)); break; } + case td_api::starTransactionPartnerTelegramAds::ID: + object("type", "telegram_ads"); + break; case td_api::starTransactionPartnerTelegram::ID: case td_api::starTransactionPartnerAppStore::ID: case td_api::starTransactionPartnerGooglePlay::ID: @@ -3989,7 +3992,6 @@ class Client::JsonStarTransactionPartner final : public td::Jsonable { LOG(ERROR) << "Receive " << to_string(*source_); object("type", "other"); break; - case td_api::starTransactionPartnerTelegramAds::ID: case td_api::starTransactionPartnerUnsupported::ID: object("type", "other"); break; From 546777ab24414e9cc419b452795b3a465431ddfb Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 30 Jun 2024 13:27:55 +0300 Subject: [PATCH 127/162] Add invoice_payload to "user" transaction partner. --- telegram-bot-api/Client.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index b48311a..5d71fef 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3980,6 +3980,14 @@ class Client::JsonStarTransactionPartner final : public td::Jsonable { auto source_user = static_cast(source_); object("type", "user"); object("user", JsonUser(source_user->bot_user_id_, client_)); + if (!source_user->invoice_payload_.empty()) { + if (!td::check_utf8(source_user->invoice_payload_)) { + LOG(WARNING) << "Receive non-UTF-8 invoice payload"; + object("invoice_payload", td::JsonRawString(source_user->invoice_payload_)); + } else { + object("invoice_payload", source_user->invoice_payload_); + } + } break; } case td_api::starTransactionPartnerTelegramAds::ID: From 3e1fee6d7a3dad669f2c38d764b9c8e2bc6a3de1 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 30 Jun 2024 13:33:06 +0300 Subject: [PATCH 128/162] Add ChatFullInfo.can_send_paid_media for channels. --- 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 5d71fef..45d9eb9 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1091,6 +1091,9 @@ class Client::JsonChat final : public td::Jsonable { if (supergroup_info->location != nullptr) { object("location", JsonChatLocation(supergroup_info->location.get())); } + if (supergroup_info->has_paid_media_allowed && !supergroup_info->is_supergroup) { + object("can_send_paid_media", td::JsonTrue()); + } } photo = supergroup_info->photo.get(); break; @@ -6952,6 +6955,7 @@ void Client::on_update(object_ptr result) { 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_; + supergroup_info->has_paid_media_allowed = full_info->has_paid_media_allowed_; break; } case td_api::updateOption::ID: { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 2e25de3..7805588 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -878,6 +878,7 @@ class Client final : public WebhookActor::Callback { bool join_by_request = false; bool has_hidden_members = false; bool has_aggressive_anti_spam_enabled = false; + bool has_paid_media_allowed = false; }; static void add_supergroup(SupergroupInfo *supergroup_info, object_ptr &&supergroup); SupergroupInfo *add_supergroup_info(int64 supergroup_id); From 4fe3ba9c99df29884067906c714291f46416200f Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 30 Jun 2024 14:05:09 +0300 Subject: [PATCH 129/162] Add Message.paid_media and ExternalReplyInfo.paid_media. --- telegram-bot-api/Client.cpp | 79 +++++++++++++++++++++++++++++++++++-- telegram-bot-api/Client.h | 2 + 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 45d9eb9..04c6af8 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1526,6 +1526,70 @@ class Client::JsonVoiceNote final : public td::Jsonable { const Client *client_; }; +class Client::JsonPaidMedia final : public td::Jsonable { + public: + JsonPaidMedia(const td_api::PaidMedia *paid_media, const Client *client) : paid_media_(paid_media), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + switch (paid_media_->get_id()) { + case td_api::paidMediaPreview::ID: { + auto media = static_cast(paid_media_); + object("type", "preview"); + if (media->width_) { + object("width", media->width_); + } + if (media->height_) { + object("height", media->height_); + } + if (media->duration_) { + object("duration", media->duration_); + } + break; + } + case td_api::paidMediaPhoto::ID: { + auto media = static_cast(paid_media_); + object("type", "photo"); + object("photo", JsonPhoto(media->photo_.get(), client_)); + break; + } + case td_api::paidMediaVideo::ID: { + auto media = static_cast(paid_media_); + object("type", "video"); + object("video", JsonVideo(media->video_.get(), client_)); + break; + } + case td_api::paidMediaUnsupported::ID: + object("type", "other"); + break; + default: + UNREACHABLE(); + } + } + + private: + const td_api::PaidMedia *paid_media_; + const Client *client_; +}; + +class Client::JsonPaidMediaInfo final : public td::Jsonable { + public: + JsonPaidMediaInfo(const td_api::messagePaidMedia *paid_media, const Client *client) + : paid_media_(paid_media), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("star_count", paid_media_->star_count_); + object("paid_media", td::json_array(paid_media_->media_, [client = client_](auto &media) { + return JsonPaidMedia(media.get(), client); + })); + } + + private: + const td_api::messagePaidMedia *paid_media_; + const Client *client_; +}; + class Client::JsonVenue final : public td::Jsonable { public: explicit JsonVenue(const td_api::venue *venue) : venue_(venue) { @@ -2593,6 +2657,11 @@ class Client::JsonExternalReplyInfo final : public td::Jsonable { object("document", JsonDocument(content->document_.get(), client_)); break; } + case td_api::messagePaidMedia::ID: { + auto content = static_cast(reply_->content_.get()); + object("paid_media", JsonPaidMediaInfo(content, client_)); + break; + } case td_api::messagePhoto::ID: { auto content = static_cast(reply_->content_.get()); CHECK(content->photo_ != nullptr); @@ -2842,6 +2911,12 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { add_caption(object, content->caption_, false); break; } + case td_api::messagePaidMedia::ID: { + auto content = static_cast(message_->content.get()); + object("paid_media", JsonPaidMediaInfo(content, client_)); + add_caption(object, content->caption_, content->show_caption_above_media_); + break; + } case td_api::messagePhoto::ID: { auto content = static_cast(message_->content.get()); CHECK(content->photo_ != nullptr); @@ -3180,8 +3255,6 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("boost_added", JsonChatBoostAdded(content)); break; } - case td_api::messagePaidMedia::ID: - break; default: UNREACHABLE(); } @@ -13632,8 +13705,6 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr Date: Sun, 30 Jun 2024 14:16:49 +0300 Subject: [PATCH 130/162] Add sendPaidMedia. --- telegram-bot-api/Client.cpp | 43 +++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 7 ++++++ 2 files changed, 50 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 04c6af8..f4258f6 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -223,6 +223,7 @@ bool Client::init_methods() { methods_.emplace("sendvideo", &Client::process_send_video_query); methods_.emplace("sendvideonote", &Client::process_send_video_note_query); methods_.emplace("sendvoice", &Client::process_send_voice_query); + methods_.emplace("sendpaidmedia", &Client::process_send_paid_media_query); methods_.emplace("sendgame", &Client::process_send_game_query); methods_.emplace("sendinvoice", &Client::process_send_invoice_query); methods_.emplace("sendlocation", &Client::process_send_location_query); @@ -9550,6 +9551,37 @@ td::Result> Client::get_input_paid_me return r_input_paid_media.move_as_ok(); } +td::Result>> Client::get_paid_media(const Query *query, + td::Slice field_name) const { + TRY_RESULT(media, get_required_string_arg(query, field_name)); + + LOG(INFO) << "Parsing JSON object: " << media; + auto r_value = json_decode(media); + if (r_value.is_error()) { + LOG(INFO) << "Can't parse JSON object: " << r_value.error(); + return td::Status::Error(400, "Can't parse paid media JSON object"); + } + + return get_paid_media(query, r_value.move_as_ok()); +} + +td::Result>> Client::get_paid_media(const Query *query, + td::JsonValue &&value) const { + if (value.type() != td::JsonValue::Type::Array) { + return td::Status::Error(400, "Expected an Array of InputPaidMedia"); + } + + td::vector> paid_media; + for (auto &input_media : value.get_array()) { + auto r_paid_media = get_input_paid_media(query, std::move(input_media)); + if (r_paid_media.is_error()) { + return td::Status::Error(400, PSLICE() << "Can't parse InputPaidMedia: " << r_paid_media.error().message()); + } + paid_media.push_back(r_paid_media.move_as_ok()); + } + return std::move(paid_media); +} + td::Result> Client::get_input_message_invoice( const Query *query) const { TRY_RESULT(title, get_required_string_arg(query, "title")); @@ -10255,6 +10287,17 @@ td::Status Client::process_send_voice_query(PromisedQueryPtr &query) { return td::Status::OK(); } +td::Status Client::process_send_paid_media_query(PromisedQueryPtr &query) { + int32 star_count = get_integer_arg(query.get(), "star_count", 0, 0, 1000000000); + TRY_RESULT(paid_media, get_paid_media(query.get(), "media")); + TRY_RESULT(caption, get_caption(query.get())); + auto show_caption_above_media = to_bool(query->arg("show_caption_above_media")); + do_send_message(make_object(star_count, std::move(paid_media), std::move(caption), + show_caption_above_media), + std::move(query)); + return td::Status::OK(); +} + td::Status Client::process_send_game_query(PromisedQueryPtr &query) { TRY_RESULT(game_short_name, get_required_string_arg(query.get(), "game_short_name")); do_send_message(make_object(my_id_, game_short_name.str()), std::move(query)); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 030e77d..92396ba 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -575,6 +575,12 @@ class Client final : public WebhookActor::Callback { td::Result> get_input_paid_media(const Query *query, td::Slice field_name) const; + td::Result>> get_paid_media(const Query *query, + td::Slice field_name) const; + + td::Result>> get_paid_media(const Query *query, + td::JsonValue &&value) const; + td::Result> get_input_message_invoice(const Query *query) const; static object_ptr get_message_send_options(bool disable_notification, @@ -642,6 +648,7 @@ class Client final : public WebhookActor::Callback { td::Status process_send_video_query(PromisedQueryPtr &query); td::Status process_send_video_note_query(PromisedQueryPtr &query); td::Status process_send_voice_query(PromisedQueryPtr &query); + td::Status process_send_paid_media_query(PromisedQueryPtr &query); td::Status process_send_game_query(PromisedQueryPtr &query); td::Status process_send_invoice_query(PromisedQueryPtr &query); td::Status process_send_location_query(PromisedQueryPtr &query); From cfa7313aedc3ae8b9de530510705bdc85bd44372 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 1 Jul 2024 01:32:50 +0300 Subject: [PATCH 131/162] Update version to 7.6. --- 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 8d38880..e16bbd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 7.5 LANGUAGES CXX) +project(TelegramBotApi VERSION 7.6 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 a5af3f6..02fdb54 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.5"; + parameters->version_ = "7.6"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats(); From d4bb6785afe74c1a175a4ea66874bde19d6d5879 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 7 Jul 2024 00:12:40 +0300 Subject: [PATCH 132/162] Update TDLib to 1.8.33. --- td | 2 +- telegram-bot-api/Client.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/td b/td index 35cfcf5..cb16492 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 35cfcf5d15981b99e8f31a2195641f035dd516c3 +Subproject commit cb164927417f22811c74cd8678ed4a5ab7cb80ba diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index f4258f6..542745e 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1009,7 +1009,7 @@ class Client::JsonChat final : public td::Jsonable { permissions->can_send_basic_messages_ && permissions->can_send_audios_ && permissions->can_send_documents_ && permissions->can_send_photos_ && permissions->can_send_videos_ && permissions->can_send_video_notes_ && permissions->can_send_voice_notes_ && permissions->can_send_polls_ && - permissions->can_send_other_messages_ && permissions->can_add_web_page_previews_ && + permissions->can_send_other_messages_ && permissions->can_add_link_previews_ && permissions->can_change_info_ && permissions->can_invite_users_ && permissions->can_pin_messages_; object("all_members_are_administrators", td::JsonBool(everyone_is_administrator)); photo = group_info->photo.get(); @@ -3256,6 +3256,8 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("boost_added", JsonChatBoostAdded(content)); break; } + case td_api::messagePaymentRefunded::ID: + break; default: UNREACHABLE(); } @@ -13101,7 +13103,7 @@ void Client::json_store_permissions(td::JsonObjectScope &object, const td_api::c object("can_send_voice_notes", td::JsonBool(permissions->can_send_voice_notes_)); object("can_send_polls", td::JsonBool(permissions->can_send_polls_)); object("can_send_other_messages", td::JsonBool(permissions->can_send_other_messages_)); - object("can_add_web_page_previews", td::JsonBool(permissions->can_add_web_page_previews_)); + object("can_add_web_page_previews", td::JsonBool(permissions->can_add_link_previews_)); 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_)); @@ -13748,6 +13750,8 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr Date: Sun, 7 Jul 2024 00:16:25 +0300 Subject: [PATCH 133/162] Add Message.refunded_payment. --- telegram-bot-api/Client.cpp | 34 ++++++++++++++++++++++++++++++---- telegram-bot-api/Client.h | 1 + 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 542745e..212524c 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2068,7 +2068,6 @@ class Client::JsonSuccessfulPaymentBot final : public td::Jsonable { if (successful_payment_->order_info_ != nullptr) { object("order_info", JsonOrderInfo(successful_payment_->order_info_.get())); } - object("telegram_payment_charge_id", successful_payment_->telegram_payment_charge_id_); object("provider_payment_charge_id", successful_payment_->provider_payment_charge_id_); } @@ -2077,6 +2076,31 @@ class Client::JsonSuccessfulPaymentBot final : public td::Jsonable { const td_api::messagePaymentSuccessfulBot *successful_payment_; }; +class Client::JsonRefundedPayment final : public td::Jsonable { + public: + explicit JsonRefundedPayment(const td_api::messagePaymentRefunded *refunded_payment) + : refunded_payment_(refunded_payment) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("currency", refunded_payment_->currency_); + object("total_amount", refunded_payment_->total_amount_); + if (!td::check_utf8(refunded_payment_->invoice_payload_)) { + LOG(WARNING) << "Receive non-UTF-8 invoice payload"; + object("invoice_payload", td::JsonRawString(refunded_payment_->invoice_payload_)); + } else { + object("invoice_payload", refunded_payment_->invoice_payload_); + } + object("telegram_payment_charge_id", refunded_payment_->telegram_payment_charge_id_); + if (!refunded_payment_->provider_payment_charge_id_.empty()) { + object("provider_payment_charge_id", refunded_payment_->provider_payment_charge_id_); + } + } + + private: + const td_api::messagePaymentRefunded *refunded_payment_; +}; + class Client::JsonEncryptedPassportElement final : public td::Jsonable { public: JsonEncryptedPassportElement(const td_api::encryptedPassportElement *element, const Client *client) @@ -3256,8 +3280,11 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("boost_added", JsonChatBoostAdded(content)); break; } - case td_api::messagePaymentRefunded::ID: + case td_api::messagePaymentRefunded::ID: { + auto content = static_cast(message_->content.get()); + object("refunded_payment", JsonRefundedPayment(content)); break; + } default: UNREACHABLE(); } @@ -13642,6 +13669,7 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr Date: Sun, 7 Jul 2024 00:17:06 +0300 Subject: [PATCH 134/162] Update version to 7.7. --- 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 e16bbd8..628b0bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 7.6 LANGUAGES CXX) +project(TelegramBotApi VERSION 7.7 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 02fdb54..82278b1 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.6"; + parameters->version_ = "7.7"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats(); From 6ba3d865ac78395595ca38592f70cbf35239e60b Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 15 Jul 2024 23:49:30 +0500 Subject: [PATCH 135/162] Build instructions updated (#615) * Build instructions updated - Fixed package manager in CentOS - Added instructions for CentOS 9 - Added instructions for Fedora 37 --- build.html | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/build.html b/build.html index e1d7c7a..b5ca362 100644 --- a/build.html +++ b/build.html @@ -201,8 +201,10 @@ + + @@ -354,7 +356,7 @@ function onOptionsChanged() { document.getElementById('buildCommandsDiv').style.display = 'block'; var use_clang = os_freebsd || os_openbsd; - if (os_linux && linux_distro !== 'Alpine' && !linux_distro.includes('CentOS')) { + if (os_linux && linux_distro !== 'Alpine' && !linux_distro.includes('CentOS') && !linux_distro.includes('Fedora')) { document.getElementById('buildCompilerDiv').style.display = 'block'; use_clang = document.getElementById('buildCompilerRadioClang').checked; } else { @@ -531,19 +533,31 @@ function onOptionsChanged() { commands.push(sudo + 'apk add ' + packages); break; case 'CentOS 7': - case 'CentOS 8': commands.push(sudo + 'yum update -y'); var packages = 'gcc-c++ make git zlib-devel openssl-devel'; - if (linux_distro === 'CentOS 7') { - commands.push(sudo + 'yum install -y centos-release-scl-rh epel-release'); - commands.push(sudo + 'yum install -y devtoolset-9-gcc devtoolset-9-gcc-c++'); - cmake = 'cmake3'; - packages += ' gperf'; - } else { + commands.push(sudo + 'yum install -y centos-release-scl-rh epel-release'); + commands.push(sudo + 'yum install -y devtoolset-9-gcc devtoolset-9-gcc-c++'); + cmake = 'cmake3'; + packages += ' gperf ' + cmake; + commands.push(sudo + 'yum install -y ' + packages); + break; + case 'CentOS 8': + case 'CentOS Stream 9': + commands.push(sudo + 'dnf update -y'); + var packages = 'gcc-c++ make git zlib-devel openssl-devel'; + if (linux_distro === 'CentOS 8') { commands.push(sudo + 'dnf --enablerepo=powertools install gperf'); + } else { + commands.push(sudo + 'dnf --enablerepo=crb install gperf'); } packages += ' ' + cmake; - commands.push(sudo + 'yum install -y ' + packages); + commands.push(sudo + 'dnf install -y ' + packages); + break; + case 'Fedora 21+': + commands.push(sudo + 'dnf update -y'); + var packages = 'gperf gcc-c++ make git zlib-devel openssl-devel'; + packages += ' ' + cmake; + commands.push(sudo + 'dnf install -y ' + packages); break; case 'Debian 8/9': case 'Debian 10+': From dd17f94d9aedf0418ee6ce27900ac8e299328b18 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 18 Jul 2024 17:21:56 +0300 Subject: [PATCH 136/162] Simplify packages list in build instructions generator. --- build.html | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/build.html b/build.html index b5ca362..5776d8a 100644 --- a/build.html +++ b/build.html @@ -534,29 +534,26 @@ function onOptionsChanged() { break; case 'CentOS 7': commands.push(sudo + 'yum update -y'); - var packages = 'gcc-c++ make git zlib-devel openssl-devel'; commands.push(sudo + 'yum install -y centos-release-scl-rh epel-release'); commands.push(sudo + 'yum install -y devtoolset-9-gcc devtoolset-9-gcc-c++'); cmake = 'cmake3'; - packages += ' gperf ' + cmake; + var packages = 'gcc-c++ make git zlib-devel openssl-devel gperf ' + cmake; commands.push(sudo + 'yum install -y ' + packages); break; case 'CentOS 8': case 'CentOS Stream 9': commands.push(sudo + 'dnf update -y'); - var packages = 'gcc-c++ make git zlib-devel openssl-devel'; if (linux_distro === 'CentOS 8') { commands.push(sudo + 'dnf --enablerepo=powertools install gperf'); } else { commands.push(sudo + 'dnf --enablerepo=crb install gperf'); } - packages += ' ' + cmake; + var packages = 'gcc-c++ make git zlib-devel openssl-devel cmake'; commands.push(sudo + 'dnf install -y ' + packages); break; case 'Fedora 21+': commands.push(sudo + 'dnf update -y'); - var packages = 'gperf gcc-c++ make git zlib-devel openssl-devel'; - packages += ' ' + cmake; + var packages = 'gperf gcc-c++ make git zlib-devel openssl-devel cmake'; commands.push(sudo + 'dnf install -y ' + packages); break; case 'Debian 8/9': From 3a53074483f2852193b137f37cb70c16449b0aa7 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 30 Jul 2024 12:28:40 +0300 Subject: [PATCH 137/162] Update TDLib to 1.8.34. --- td | 2 +- telegram-bot-api/Client.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/td b/td index cb16492..1fa2a37 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit cb164927417f22811c74cd8678ed4a5ab7cb80ba +Subproject commit 1fa2a372a88c26369dcac2ce476166531df74a77 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 212524c..36007ec 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3285,6 +3285,8 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("refunded_payment", JsonRefundedPayment(content)); break; } + case td_api::messageGiftedStars::ID: + break; default: UNREACHABLE(); } @@ -4085,7 +4087,7 @@ class Client::JsonStarTransactionPartner final : public td::Jsonable { case td_api::starTransactionPartnerBot::ID: { auto source_user = static_cast(source_); object("type", "user"); - object("user", JsonUser(source_user->bot_user_id_, client_)); + object("user", JsonUser(source_user->user_id_, client_)); if (!source_user->invoice_payload_.empty()) { if (!td::check_utf8(source_user->invoice_payload_)) { LOG(WARNING) << "Receive non-UTF-8 invoice payload"; @@ -4102,6 +4104,7 @@ class Client::JsonStarTransactionPartner final : public td::Jsonable { case td_api::starTransactionPartnerTelegram::ID: case td_api::starTransactionPartnerAppStore::ID: case td_api::starTransactionPartnerGooglePlay::ID: + case td_api::starTransactionPartnerUser::ID: case td_api::starTransactionPartnerChannel::ID: LOG(ERROR) << "Receive " << to_string(*source_); object("type", "other"); @@ -13778,6 +13781,8 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr Date: Tue, 30 Jul 2024 13:05:42 +0300 Subject: [PATCH 138/162] Support pinChatMessage for business messages. --- telegram-bot-api/Client.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 36007ec..5badda4 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -11302,10 +11302,21 @@ td::Status Client::process_set_chat_description_query(PromisedQueryPtr &query) { } td::Status Client::process_pin_chat_message_query(PromisedQueryPtr &query) { + auto business_connection_id = query->arg("business_connection_id"); auto chat_id = query->arg("chat_id"); auto message_id = get_message_id(query.get()); auto disable_notification = to_bool(query->arg("disable_notification")); + if (!business_connection_id.empty()) { + check_business_connection_chat_id( + business_connection_id.str(), chat_id.str(), std::move(query), + [this, message_id](const BusinessConnection *business_connection, int64 chat_id, PromisedQueryPtr query) { + send_request( + make_object(business_connection->id_, chat_id, message_id, true), + td::make_unique(std::move(query))); + }); + return td::Status::OK(); + } check_message(chat_id, message_id, false, AccessRights::Write, "message to pin", std::move(query), [this, disable_notification](int64 chat_id, int64 message_id, PromisedQueryPtr query) { send_request(make_object(chat_id, message_id, disable_notification, false), From 16de9313b0d2960b702811263ba70998bcb553da Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 30 Jul 2024 13:10:46 +0300 Subject: [PATCH 139/162] Support unpinChatMessage for business messages. --- telegram-bot-api/Client.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 5badda4..d708db7 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -11326,9 +11326,21 @@ td::Status Client::process_pin_chat_message_query(PromisedQueryPtr &query) { } td::Status Client::process_unpin_chat_message_query(PromisedQueryPtr &query) { + auto business_connection_id = query->arg("business_connection_id"); auto chat_id = query->arg("chat_id"); auto message_id = get_message_id(query.get()); + if (!business_connection_id.empty()) { + check_business_connection_chat_id( + business_connection_id.str(), chat_id.str(), std::move(query), + [this, message_id](const BusinessConnection *business_connection, int64 chat_id, PromisedQueryPtr query) { + send_request( + make_object(business_connection->id_, chat_id, message_id, false), + td::make_unique(std::move(query))); + }); + return td::Status::OK(); + } + if (message_id == 0) { check_chat(chat_id, AccessRights::Write, std::move(query), [this](int64 chat_id, PromisedQueryPtr query) { send_request(make_object(chat_id), From 127964a3f289d83c6730dc93f4a87d1b7c729d53 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 30 Jul 2024 13:43:00 +0300 Subject: [PATCH 140/162] Add User.has_main_web_app. --- telegram-bot-api/Client.cpp | 2 ++ telegram-bot-api/Client.h | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index d708db7..73303ba 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -420,6 +420,7 @@ class Client::JsonUser final : public td::Jsonable { object("can_read_all_group_messages", td::JsonBool(user_info->can_read_all_group_messages)); object("supports_inline_queries", td::JsonBool(user_info->is_inline_bot)); object("can_connect_to_business", td::JsonBool(user_info->can_connect_to_business)); + object("has_main_web_app", td::JsonBool(user_info->has_main_web_app)); } } @@ -12858,6 +12859,7 @@ void Client::add_user(UserInfo *user_info, object_ptr &&user) { user_info->can_read_all_group_messages = bot->can_read_all_group_messages_; user_info->is_inline_bot = bot->is_inline_; user_info->can_connect_to_business = bot->can_connect_to_business_; + user_info->has_main_web_app = bot->has_main_web_app_; break; } case td_api::userTypeDeleted::ID: diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 0ab6ee2..bc9edbb 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -841,9 +841,10 @@ class Client final : public WebhookActor::Callback { bool can_join_groups = false; bool can_read_all_group_messages = false; bool can_connect_to_business = false; - bool is_inline_bot = false; + bool has_main_web_app = false; bool has_private_forwards = false; bool has_restricted_voice_and_video_messages = false; + bool is_inline_bot = false; bool is_premium = false; bool added_to_attachment_menu = false; }; From 12bbe26692b8c6e347aaf3e32e0e9d11b86bb56d Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 30 Jul 2024 16:21:23 +0300 Subject: [PATCH 141/162] Update version to 7.8. --- 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 628b0bd..1451ed6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 7.7 LANGUAGES CXX) +project(TelegramBotApi VERSION 7.8 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 82278b1..3633a66 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.7"; + parameters->version_ = "7.8"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats(); From ffe39d4114df56161f2ecf6289729ba14d9a5406 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 13 Aug 2024 14:51:15 +0300 Subject: [PATCH 142/162] Update TDLib to 1.8.35. --- td | 2 +- telegram-bot-api/Client.cpp | 31 +++++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/td b/td index 1fa2a37..8d08b34 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 1fa2a372a88c26369dcac2ce476166531df74a77 +Subproject commit 8d08b34e22a08e58db8341839c4e18ee06c516c5 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 73303ba..fb81fa2 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -709,6 +709,8 @@ class Client::JsonReactionType final : public td::Jsonable { object("custom_emoji_id", td::to_string(static_cast(reaction_type_)->custom_emoji_id_)); break; + case td_api::reactionTypePaid::ID: + break; default: UNREACHABLE(); } @@ -4089,13 +4091,25 @@ class Client::JsonStarTransactionPartner final : public td::Jsonable { auto source_user = static_cast(source_); object("type", "user"); object("user", JsonUser(source_user->user_id_, client_)); - if (!source_user->invoice_payload_.empty()) { - if (!td::check_utf8(source_user->invoice_payload_)) { - LOG(WARNING) << "Receive non-UTF-8 invoice payload"; - object("invoice_payload", td::JsonRawString(source_user->invoice_payload_)); - } else { - object("invoice_payload", source_user->invoice_payload_); + CHECK(source_user->purpose_ != nullptr); + switch (source_user->purpose_->get_id()) { + case td_api::botTransactionPurposeInvoicePayment::ID: { + auto purpose = + static_cast(source_user->purpose_.get()); + if (!purpose->invoice_payload_.empty()) { + if (!td::check_utf8(purpose->invoice_payload_)) { + LOG(WARNING) << "Receive non-UTF-8 invoice payload"; + object("invoice_payload", td::JsonRawString(purpose->invoice_payload_)); + } else { + object("invoice_payload", purpose->invoice_payload_); + } + } + break; } + case td_api::botTransactionPurposePaidMedia::ID: + break; + default: + UNREACHABLE(); } break; } @@ -4106,6 +4120,7 @@ class Client::JsonStarTransactionPartner final : public td::Jsonable { case td_api::starTransactionPartnerAppStore::ID: case td_api::starTransactionPartnerGooglePlay::ID: case td_api::starTransactionPartnerUser::ID: + case td_api::starTransactionPartnerBusiness::ID: case td_api::starTransactionPartnerChannel::ID: LOG(ERROR) << "Receive " << to_string(*source_); object("type", "other"); @@ -10978,8 +10993,8 @@ td::Status Client::process_create_invoice_link_query(PromisedQueryPtr &query) { td::Status Client::process_get_star_transactions_query(PromisedQueryPtr &query) { auto offset = get_integer_arg(query.get(), "offset", 0, 0); auto limit = get_integer_arg(query.get(), "limit", 100, 1, 100); - send_request(make_object(make_object(my_id_), nullptr, - td::to_string(offset), limit), + send_request(make_object(make_object(my_id_), td::string(), + nullptr, td::to_string(offset), limit), td::make_unique(this, std::move(query))); return td::Status::OK(); } From 3c4656b5394ebded4c80aca1bfefa41fdda8da69 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 13 Aug 2024 15:24:19 +0300 Subject: [PATCH 143/162] Support paid reactions. --- telegram-bot-api/Client.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index fb81fa2..1cc0084 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -710,6 +710,7 @@ class Client::JsonReactionType final : public td::Jsonable { td::to_string(static_cast(reaction_type_)->custom_emoji_id_)); break; case td_api::reactionTypePaid::ID: + object("type", "paid"); break; default: UNREACHABLE(); From e171396b8a051a148dbca6c81b0ca372cb9860a2 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 13 Aug 2024 15:28:48 +0300 Subject: [PATCH 144/162] Support chatMemberStatusMember.member_until_date. --- telegram-bot-api/Client.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 1cc0084..51d9dc4 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3710,8 +3710,13 @@ class Client::JsonChatMember final : public td::Jsonable { } break; } - case td_api::chatMemberStatusMember::ID: + case td_api::chatMemberStatusMember::ID: { + auto member = static_cast(member_->status_.get()); + if (member->member_until_date_ > 0) { + object("until_date", member->member_until_date_); + } break; + } case td_api::chatMemberStatusRestricted::ID: if (chat_type_ == Client::ChatType::Supergroup) { auto restricted = static_cast(member_->status_.get()); From af5f55b20601f7391559434990a5eba0f9448fa9 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 13 Aug 2024 15:46:37 +0300 Subject: [PATCH 145/162] Add subscription information to ChatInviteLink. --- telegram-bot-api/Client.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 51d9dc4..e02c120 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -887,6 +887,10 @@ class Client::JsonChatInviteLink final : public td::Jsonable { if (chat_invite_link_->pending_join_request_count_ != 0) { object("pending_join_request_count", chat_invite_link_->pending_join_request_count_); } + if (chat_invite_link_->subscription_pricing_ != nullptr) { + object("subscription_period", chat_invite_link_->subscription_pricing_->period_); + object("subscription_price", chat_invite_link_->subscription_pricing_->star_count_); + } object("creates_join_request", td::JsonBool(chat_invite_link_->creates_join_request_)); object("is_primary", td::JsonBool(chat_invite_link_->is_primary_)); object("is_revoked", td::JsonBool(chat_invite_link_->is_revoked_)); From 6478c25096ec1113e9617fa347e9acb38402d332 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 13 Aug 2024 16:00:42 +0300 Subject: [PATCH 146/162] Support botTransactionPurposePaidMedia. --- telegram-bot-api/Client.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index e02c120..4ce09f9 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4116,8 +4116,13 @@ class Client::JsonStarTransactionPartner final : public td::Jsonable { } break; } - case td_api::botTransactionPurposePaidMedia::ID: + case td_api::botTransactionPurposePaidMedia::ID: { + auto purpose = static_cast(source_user->purpose_.get()); + object("paid_media", td::json_array(purpose->media_, [client = client_](auto &media) { + return JsonPaidMedia(media.get(), client); + })); break; + } default: UNREACHABLE(); } From 76e5ed31c062ce60b6d3cd7761e4f1a4129882c9 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 14 Aug 2024 00:26:20 +0300 Subject: [PATCH 147/162] Add method createChatSubscriptionInviteLink. --- telegram-bot-api/Client.cpp | 17 +++++++++++++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 18 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 4ce09f9..b6e3467 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -258,6 +258,7 @@ bool Client::init_methods() { methods_.emplace("answerprecheckoutquery", &Client::process_answer_pre_checkout_query_query); methods_.emplace("exportchatinvitelink", &Client::process_export_chat_invite_link_query); methods_.emplace("createchatinvitelink", &Client::process_create_chat_invite_link_query); + methods_.emplace("createchatsubscriptioninvitelink", &Client::process_create_chat_subscription_invite_link_query); methods_.emplace("editchatinvitelink", &Client::process_edit_chat_invite_link_query); methods_.emplace("revokechatinvitelink", &Client::process_revoke_chat_invite_link_query); methods_.emplace("getbusinessconnection", &Client::process_get_business_connection_query); @@ -11201,6 +11202,22 @@ td::Status Client::process_create_chat_invite_link_query(PromisedQueryPtr &query return td::Status::OK(); } +td::Status Client::process_create_chat_subscription_invite_link_query(PromisedQueryPtr &query) { + auto chat_id = query->arg("chat_id"); + auto name = query->arg("name"); + auto subscription_period = get_integer_arg(query.get(), "subscription_period", 0, 0, 1000000000); + auto subscription_price = get_integer_arg(query.get(), "subscription_price", 0, 0, 1000000); + + check_chat(chat_id, AccessRights::Write, std::move(query), + [this, name = name.str(), subscription_period, subscription_price](int64 chat_id, PromisedQueryPtr query) { + send_request(make_object( + chat_id, name, + make_object(subscription_period, subscription_price)), + td::make_unique(this, std::move(query))); + }); + return td::Status::OK(); +} + td::Status Client::process_edit_chat_invite_link_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); auto invite_link = query->arg("invite_link"); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index bc9edbb..0b0b3f6 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -683,6 +683,7 @@ class Client final : public WebhookActor::Callback { td::Status process_answer_pre_checkout_query_query(PromisedQueryPtr &query); td::Status process_export_chat_invite_link_query(PromisedQueryPtr &query); td::Status process_create_chat_invite_link_query(PromisedQueryPtr &query); + td::Status process_create_chat_subscription_invite_link_query(PromisedQueryPtr &query); td::Status process_edit_chat_invite_link_query(PromisedQueryPtr &query); td::Status process_revoke_chat_invite_link_query(PromisedQueryPtr &query); td::Status process_get_business_connection_query(PromisedQueryPtr &query); From 961a19e1a01f50555ee4d758a8d02cbacaf084c1 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 14 Aug 2024 00:29:32 +0300 Subject: [PATCH 148/162] Add method editChatSubscriptionInviteLink. --- telegram-bot-api/Client.cpp | 14 ++++++++++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 15 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index b6e3467..86bd10d 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -260,6 +260,7 @@ bool Client::init_methods() { methods_.emplace("createchatinvitelink", &Client::process_create_chat_invite_link_query); methods_.emplace("createchatsubscriptioninvitelink", &Client::process_create_chat_subscription_invite_link_query); methods_.emplace("editchatinvitelink", &Client::process_edit_chat_invite_link_query); + methods_.emplace("editchatsubscriptioninvitelink", &Client::process_edit_chat_subscription_invite_link_query); methods_.emplace("revokechatinvitelink", &Client::process_revoke_chat_invite_link_query); methods_.emplace("getbusinessconnection", &Client::process_get_business_connection_query); methods_.emplace("getchat", &Client::process_get_chat_query); @@ -11236,6 +11237,19 @@ td::Status Client::process_edit_chat_invite_link_query(PromisedQueryPtr &query) return td::Status::OK(); } +td::Status Client::process_edit_chat_subscription_invite_link_query(PromisedQueryPtr &query) { + auto chat_id = query->arg("chat_id"); + auto invite_link = query->arg("invite_link"); + auto name = query->arg("name"); + + check_chat(chat_id, AccessRights::Write, std::move(query), + [this, invite_link = invite_link.str(), name = name.str()](int64 chat_id, PromisedQueryPtr query) { + send_request(make_object(chat_id, invite_link, name), + td::make_unique(this, std::move(query))); + }); + return td::Status::OK(); +} + td::Status Client::process_revoke_chat_invite_link_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); auto invite_link = query->arg("invite_link"); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 0b0b3f6..3fef529 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -685,6 +685,7 @@ class Client final : public WebhookActor::Callback { td::Status process_create_chat_invite_link_query(PromisedQueryPtr &query); td::Status process_create_chat_subscription_invite_link_query(PromisedQueryPtr &query); td::Status process_edit_chat_invite_link_query(PromisedQueryPtr &query); + td::Status process_edit_chat_subscription_invite_link_query(PromisedQueryPtr &query); td::Status process_revoke_chat_invite_link_query(PromisedQueryPtr &query); td::Status process_get_business_connection_query(PromisedQueryPtr &query); td::Status process_get_chat_query(PromisedQueryPtr &query); From 06e2e31aeaa9bdfc2b3e11bb3e4761241373b7cd Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 14 Aug 2024 05:16:39 +0300 Subject: [PATCH 149/162] Update version to 7.9. --- 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 1451ed6..b5e56ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 7.8 LANGUAGES CXX) +project(TelegramBotApi VERSION 7.9 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 3633a66..9035a3b 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.8"; + parameters->version_ = "7.9"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats(); From 6e5d607b905578f557af855dc465306eaa3fd241 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 27 Aug 2024 15:55:54 +0300 Subject: [PATCH 150/162] Add and use Client::is_special_error_code. --- telegram-bot-api/Client.cpp | 42 ++++++++++++++++++++----------------- telegram-bot-api/Client.h | 2 ++ 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 86bd10d..87c63f3 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -39,6 +39,24 @@ namespace telegram_bot_api { using td_api::make_object; using td_api::move_object_as; +Client::Client(td::ActorShared<> parent, const td::string &bot_token, bool is_test_dc, int64 tqueue_id, + std::shared_ptr parameters, td::ActorId stat_actor) + : parent_(std::move(parent)) + , bot_token_(bot_token) + , bot_token_id_("") + , is_test_dc_(is_test_dc) + , tqueue_id_(tqueue_id) + , parameters_(std::move(parameters)) + , stat_actor_(std::move(stat_actor)) { + static auto is_inited = init_methods(); + CHECK(is_inited); +} + +Client::~Client() { + td::Scheduler::instance()->destroy_on_scheduler(SharedData::get_file_gc_scheduler_id(), messages_, users_, groups_, + supergroups_, chats_, sticker_set_names_); +} + int Client::get_retry_after_time(td::Slice error_message) { td::Slice prefix = "Too Many Requests: retry after "; if (td::begins_with(error_message, prefix)) { @@ -179,22 +197,8 @@ void Client::fail_query_with_error(PromisedQueryPtr &&query, object_ptrcode_, error->message_, default_message); } -Client::Client(td::ActorShared<> parent, const td::string &bot_token, bool is_test_dc, int64 tqueue_id, - std::shared_ptr parameters, td::ActorId stat_actor) - : parent_(std::move(parent)) - , bot_token_(bot_token) - , bot_token_id_("") - , is_test_dc_(is_test_dc) - , tqueue_id_(tqueue_id) - , parameters_(std::move(parameters)) - , stat_actor_(std::move(stat_actor)) { - static auto is_inited = init_methods(); - CHECK(is_inited); -} - -Client::~Client() { - td::Scheduler::instance()->destroy_on_scheduler(SharedData::get_file_gc_scheduler_id(), messages_, users_, groups_, - supergroups_, chats_, sticker_set_names_); +bool Client::is_special_error_code(int32 error_code) { + return error_code == 401 || error_code == 429 || error_code >= 500; } bool Client::init_methods() { @@ -5281,7 +5285,7 @@ class Client::TdOnGetChatPinnedMessageCallback final : public TdQueryCallback { int64 pinned_message_id = 0; if (result->get_id() == td_api::error::ID) { auto error = move_object_as(result); - if (error->code_ == 429) { + if (is_special_error_code(error->code_)) { return fail_query_with_error(std::move(query_), std::move(error)); } else if (error->code_ != 404 && error->message_ != "CHANNEL_PRIVATE") { LOG(ERROR) << "Failed to get chat pinned message: " << to_string(error); @@ -5349,7 +5353,7 @@ class Client::TdOnGetChatPinnedMessageToUnpinCallback final : public TdQueryCall int64 pinned_message_id = 0; if (result->get_id() == td_api::error::ID) { auto error = move_object_as(result); - if (error->code_ == 429) { + if (is_special_error_code(error->code_)) { return fail_query_with_error(std::move(query_), std::move(error)); } else { return fail_query_with_error(std::move(query_), 400, "Message to unpin not found"); @@ -9959,7 +9963,7 @@ void Client::on_message_send_failed(int64 chat_id, int64 old_message_id, int64 n auto &query = *pending_send_message_queries_[query_id]; if (query.is_multisend) { if (query.error == nullptr || query.error->message_ == "Group send failed") { - if (error->code_ == 401 || error->code_ == 429 || error->code_ >= 500 || error->message_ == "Group send failed") { + if (is_special_error_code(error->code_) || error->message_ == "Group send failed") { query.error = std::move(error); } else { auto pos = (query.total_message_count - query.awaited_message_count + 1); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 3fef529..bc12bcb 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -810,6 +810,8 @@ class Client final : public WebhookActor::Callback { static void fail_query_with_error(PromisedQueryPtr &&query, object_ptr error, td::Slice default_message = td::Slice()); + static bool is_special_error_code(int32 error_code); + class JsonUpdates; void do_get_updates(int32 offset, int32 limit, int32 timeout, PromisedQueryPtr query); From 240eb7b4a909458bbec116af5d712905a74d2884 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 27 Aug 2024 17:42:44 +0300 Subject: [PATCH 151/162] Update TDLib to 1.8.36. --- td | 2 +- telegram-bot-api/Client.cpp | 86 +++++++++++++++++++++++-------------- 2 files changed, 55 insertions(+), 33 deletions(-) diff --git a/td b/td index 8d08b34..87d8810 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 8d08b34e22a08e58db8341839c4e18ee06c516c5 +Subproject commit 87d881071fe514936bb17029e96761141287d2be diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 87c63f3..dd31e7f 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2421,8 +2421,7 @@ class Client::JsonChatShared final : public td::Jsonable { class Client::JsonGiveaway final : public td::Jsonable { public: - JsonGiveaway(const td_api::messagePremiumGiveaway *giveaway, const Client *client) - : giveaway_(giveaway), client_(client) { + JsonGiveaway(const td_api::messageGiveaway *giveaway, const Client *client) : giveaway_(giveaway), client_(client) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); @@ -2447,19 +2446,29 @@ class Client::JsonGiveaway final : public td::Jsonable { 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_); + switch (giveaway_->prize_->get_id()) { + case td_api::giveawayPrizePremium::ID: { + auto month_count = static_cast(giveaway_->prize_.get())->month_count_; + if (month_count > 0) { + object("premium_subscription_month_count", month_count); + } + break; + } + case td_api::giveawayPrizeStars::ID: + break; + default: + UNREACHABLE(); } } private: - const td_api::messagePremiumGiveaway *giveaway_; + const td_api::messageGiveaway *giveaway_; const Client *client_; }; class Client::JsonGiveawayWinners final : public td::Jsonable { public: - JsonGiveawayWinners(const td_api::messagePremiumGiveawayWinners *giveaway_winners, const Client *client) + JsonGiveawayWinners(const td_api::messageGiveawayWinners *giveaway_winners, const Client *client) : giveaway_winners_(giveaway_winners), client_(client) { } void store(td::JsonValueScope *scope) const { @@ -2476,8 +2485,19 @@ class Client::JsonGiveawayWinners final : public td::Jsonable { 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_); + switch (giveaway_winners_->prize_->get_id()) { + case td_api::giveawayPrizePremium::ID: { + auto month_count = + static_cast(giveaway_winners_->prize_.get())->month_count_; + if (month_count > 0) { + object("premium_subscription_month_count", month_count); + } + break; + } + case td_api::giveawayPrizeStars::ID: + break; + default: + UNREACHABLE(); } if (!giveaway_winners_->prize_description_.empty()) { object("prize_description", giveaway_winners_->prize_description_); @@ -2490,14 +2510,13 @@ class Client::JsonGiveawayWinners final : public td::Jsonable { } private: - const td_api::messagePremiumGiveawayWinners *giveaway_winners_; + const td_api::messageGiveawayWinners *giveaway_winners_; const Client *client_; }; class Client::JsonGiveawayCompleted final : public td::Jsonable { public: - JsonGiveawayCompleted(const td_api::messagePremiumGiveawayCompleted *giveaway_completed, int64 chat_id, - const Client *client) + JsonGiveawayCompleted(const td_api::messageGiveawayCompleted *giveaway_completed, int64 chat_id, const Client *client) : giveaway_completed_(giveaway_completed), chat_id_(chat_id), client_(client) { } void store(td::JsonValueScope *scope) const { @@ -2514,7 +2533,7 @@ class Client::JsonGiveawayCompleted final : public td::Jsonable { } private: - const td_api::messagePremiumGiveawayCompleted *giveaway_completed_; + const td_api::messageGiveawayCompleted *giveaway_completed_; int64 chat_id_; const Client *client_; }; @@ -2767,13 +2786,13 @@ class Client::JsonExternalReplyInfo final : public td::Jsonable { } case td_api::messageUnsupported::ID: break; - case td_api::messagePremiumGiveaway::ID: { - auto content = static_cast(reply_->content_.get()); + case td_api::messageGiveaway::ID: { + auto content = static_cast(reply_->content_.get()); object("giveaway", JsonGiveaway(content, client_)); break; } - case td_api::messagePremiumGiveawayWinners::ID: { - auto content = static_cast(reply_->content_.get()); + case td_api::messageGiveawayWinners::ID: { + auto content = static_cast(reply_->content_.get()); object("giveaway_winners", JsonGiveawayWinners(content, client_)); break; } @@ -3271,21 +3290,21 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { } case td_api::messagePremiumGiftCode::ID: break; - case td_api::messagePremiumGiveawayCreated::ID: + case td_api::messageGiveawayCreated::ID: object("giveaway_created", JsonEmptyObject()); break; - case td_api::messagePremiumGiveaway::ID: { - auto content = static_cast(message_->content.get()); + case td_api::messageGiveaway::ID: { + auto content = static_cast(message_->content.get()); object("giveaway", JsonGiveaway(content, client_)); break; } - case td_api::messagePremiumGiveawayWinners::ID: { - auto content = static_cast(message_->content.get()); + case td_api::messageGiveawayWinners::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()); + case td_api::messageGiveawayCompleted::ID: { + auto content = static_cast(message_->content.get()); object("giveaway_completed", JsonGiveawayCompleted(content, message_->chat_id, client_)); break; } @@ -3301,6 +3320,8 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { } case td_api::messageGiftedStars::ID: break; + case td_api::messageGiveawayPrizeStars::ID: + break; default: UNREACHABLE(); } @@ -4142,7 +4163,7 @@ class Client::JsonStarTransactionPartner final : public td::Jsonable { case td_api::starTransactionPartnerGooglePlay::ID: case td_api::starTransactionPartnerUser::ID: case td_api::starTransactionPartnerBusiness::ID: - case td_api::starTransactionPartnerChannel::ID: + case td_api::starTransactionPartnerChat::ID: LOG(ERROR) << "Receive " << to_string(*source_); object("type", "other"); break; @@ -10362,7 +10383,7 @@ td::Status Client::process_send_paid_media_query(PromisedQueryPtr &query) { TRY_RESULT(caption, get_caption(query.get())); auto show_caption_above_media = to_bool(query->arg("show_caption_above_media")); do_send_message(make_object(star_count, std::move(paid_media), std::move(caption), - show_caption_above_media), + show_caption_above_media, td::string()), std::move(query)); return td::Status::OK(); } @@ -13758,10 +13779,10 @@ 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::messageGiveawayCompleted::ID: + return static_cast(message->content_.get())->giveaway_message_id_; case td_api::messagePaymentSuccessful::ID: UNREACHABLE(); return static_cast(0); From c571a9ee5b9c0152b140f38e03f93490a307dfb0 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 28 Aug 2024 11:54:13 +0300 Subject: [PATCH 152/162] Use td_api::getStickerSetName instead of td_api::getStickerSet. --- telegram-bot-api/Client.cpp | 110 +++++++++++++++++++++--------------- telegram-bot-api/Client.h | 2 +- 2 files changed, 65 insertions(+), 47 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index dd31e7f..cc3e12d 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -5182,10 +5182,10 @@ class Client::TdOnGetStickerSetCallback final : public TdQueryCallback { nullptr); } - CHECK(result->get_id() == td_api::stickerSet::ID); + CHECK(result->get_id() == td_api::text::ID); client_->on_get_sticker_set(set_id_, new_callback_query_user_id_, new_message_chat_id_, new_message_business_connection_id_, new_business_callback_query_user_id_, - move_object_as(result)); + move_object_as(result)); } private: @@ -5199,9 +5199,13 @@ class Client::TdOnGetStickerSetCallback final : public TdQueryCallback { class Client::TdOnGetChatCustomEmojiStickerSetCallback final : public TdQueryCallback { public: - TdOnGetChatCustomEmojiStickerSetCallback(Client *client, int64 chat_id, int64 pinned_message_id, + TdOnGetChatCustomEmojiStickerSetCallback(Client *client, int64 sticker_set_id, 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)) { + : client_(client) + , sticker_set_id_(sticker_set_id) + , chat_id_(chat_id) + , pinned_message_id_(pinned_message_id) + , query_(std::move(query)) { } void on_result(object_ptr result) final { @@ -5212,9 +5216,9 @@ class Client::TdOnGetChatCustomEmojiStickerSetCallback final : public TdQueryCal 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_); + CHECK(result->get_id() == td_api::text::ID); + auto sticker_set_name = move_object_as(result); + client_->on_get_sticker_set_name(sticker_set_id_, sticker_set_name->text_); } answer_query(JsonChat(chat_id_, client_, true, pinned_message_id_), std::move(query_)); @@ -5222,6 +5226,7 @@ class Client::TdOnGetChatCustomEmojiStickerSetCallback final : public TdQueryCal private: Client *client_; + int64 sticker_set_id_; int64 chat_id_; int64 pinned_message_id_; PromisedQueryPtr query_; @@ -5229,9 +5234,13 @@ class Client::TdOnGetChatCustomEmojiStickerSetCallback final : public TdQueryCal class Client::TdOnGetChatBusinessStartPageStickerSetCallback final : public TdQueryCallback { public: - TdOnGetChatBusinessStartPageStickerSetCallback(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)) { + TdOnGetChatBusinessStartPageStickerSetCallback(Client *client, int64 sticker_set_id, int64 chat_id, + int64 pinned_message_id, PromisedQueryPtr query) + : client_(client) + , sticker_set_id_(sticker_set_id) + , chat_id_(chat_id) + , pinned_message_id_(pinned_message_id) + , query_(std::move(query)) { } void on_result(object_ptr result) final { @@ -5245,9 +5254,9 @@ class Client::TdOnGetChatBusinessStartPageStickerSetCallback final : public TdQu user_info->business_info->start_page_->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_); + CHECK(result->get_id() == td_api::text::ID); + auto sticker_set_name = move_object_as(result); + client_->on_get_sticker_set_name(sticker_set_id_, sticker_set_name->text_); } answer_query(JsonChat(chat_id_, client_, true, pinned_message_id_), std::move(query_)); @@ -5255,6 +5264,7 @@ class Client::TdOnGetChatBusinessStartPageStickerSetCallback final : public TdQu private: Client *client_; + int64 sticker_set_id_; int64 chat_id_; int64 pinned_message_id_; PromisedQueryPtr query_; @@ -5262,8 +5272,13 @@ class Client::TdOnGetChatBusinessStartPageStickerSetCallback final : public TdQu class Client::TdOnGetChatStickerSetCallback final : public TdQueryCallback { public: - TdOnGetChatStickerSetCallback(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)) { + TdOnGetChatStickerSetCallback(Client *client, int64 sticker_set_id, int64 chat_id, int64 pinned_message_id, + PromisedQueryPtr query) + : client_(client) + , sticker_set_id_(sticker_set_id) + , chat_id_(chat_id) + , pinned_message_id_(pinned_message_id) + , query_(std::move(query)) { } void on_result(object_ptr result) final { @@ -5274,16 +5289,16 @@ class Client::TdOnGetChatStickerSetCallback final : public TdQueryCallback { if (result->get_id() == td_api::error::ID) { 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_); + CHECK(result->get_id() == td_api::text::ID); + auto sticker_set_name = move_object_as(result); + client_->on_get_sticker_set_name(sticker_set_id_, sticker_set_name->text_); } 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), + return client_->send_request(make_object(sticker_set_id), td::make_unique( - client_, chat_id_, pinned_message_id_, std::move(query_))); + client_, sticker_set_id, chat_id_, pinned_message_id_, std::move(query_))); } answer_query(JsonChat(chat_id_, client_, true, pinned_message_id_), std::move(query_)); @@ -5291,6 +5306,7 @@ class Client::TdOnGetChatStickerSetCallback final : public TdQueryCallback { private: Client *client_; + int64 sticker_set_id_; int64 chat_id_; int64 pinned_message_id_; PromisedQueryPtr query_; @@ -5327,16 +5343,16 @@ class Client::TdOnGetChatPinnedMessageCallback final : public TdQueryCallback { auto sticker_set_id = supergroup_info->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_))); + return client_->send_request(make_object(sticker_set_id), + td::make_unique( + client_, sticker_set_id, 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), + return client_->send_request(make_object(sticker_set_id), td::make_unique( - client_, chat_id_, pinned_message_id, std::move(query_))); + client_, sticker_set_id, chat_id_, pinned_message_id, std::move(query_))); } } else if (chat_info->type == ChatInfo::Type::Private) { auto user_info = client_->get_user_info(chat_info->user_id); @@ -5347,9 +5363,9 @@ class Client::TdOnGetChatPinnedMessageCallback final : public TdQueryCallback { if (sticker != nullptr) { auto sticker_set_id = 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), + return client_->send_request(make_object(sticker_set_id), td::make_unique( - client_, chat_id_, pinned_message_id, std::move(query_))); + client_, sticker_set_id, chat_id_, pinned_message_id, std::move(query_))); } } } @@ -5825,8 +5841,8 @@ class Client::TdOnReturnStickerSetCallback final : public TdQueryCallback { class Client::TdOnGetStickerSetPromiseCallback final : public TdQueryCallback { public: - TdOnGetStickerSetPromiseCallback(Client *client, td::Promise &&promise) - : client_(client), promise_(std::move(promise)) { + TdOnGetStickerSetPromiseCallback(Client *client, int64 sticker_set_id, td::Promise &&promise) + : client_(client), sticker_set_id_(sticker_set_id), promise_(std::move(promise)) { } void on_result(object_ptr result) final { @@ -5835,14 +5851,15 @@ class Client::TdOnGetStickerSetPromiseCallback final : public TdQueryCallback { return promise_.set_error(td::Status::Error(error->code_, error->message_)); } - 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_); + CHECK(result->get_id() == td_api::text::ID); + auto sticker_set_name = move_object_as(result); + client_->on_get_sticker_set_name(sticker_set_id_, sticker_set_name->text_); promise_.set_value(td::Unit()); } private: Client *client_; + int64 sticker_set_id_; td::Promise promise_; }; @@ -5874,8 +5891,9 @@ class Client::TdOnGetStickersCallback final : public TdQueryCallback { auto lock = mpas.get_promise(); for (auto sticker_set_id : sticker_set_ids) { - client_->send_request(make_object(sticker_set_id), - td::make_unique(client_, mpas.get_promise())); + client_->send_request( + make_object(sticker_set_id), + td::make_unique(client_, sticker_set_id, mpas.get_promise())); } lock.set_value(td::Unit()); } @@ -6145,7 +6163,7 @@ void Client::on_get_callback_query_message(object_ptr message, void Client::on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, int64 new_message_chat_id, const td::string &new_message_business_connection_id, - int64 new_business_callback_query_user_id, object_ptr sticker_set) { + int64 new_business_callback_query_user_id, object_ptr sticker_set_name) { if (new_callback_query_user_id != 0) { auto &queue = new_callback_query_queues_[new_callback_query_user_id]; CHECK(queue.has_active_request_); @@ -6178,8 +6196,8 @@ void Client::on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, CHECK(set_id != 0); if (set_id != GREAT_MINDS_SET_ID) { td::string &set_name = sticker_set_names_[set_id]; - if (sticker_set != nullptr) { - set_name = std::move(sticker_set->name_); + if (sticker_set_name != nullptr) { + set_name = std::move(sticker_set_name->text_); } } @@ -13517,7 +13535,7 @@ void Client::process_new_callback_query_queue(int64 user_id, int state) { if (!have_sticker_set_name(message_sticker_set_id)) { queue.has_active_request_ = true; return send_request( - make_object(message_sticker_set_id), + make_object(message_sticker_set_id), td::make_unique(this, message_sticker_set_id, user_id, 0, td::string(), 0)); } auto reply_to_message_id = get_same_chat_reply_to_message_id(message_info); @@ -13528,7 +13546,7 @@ void Client::process_new_callback_query_queue(int64 user_id, int state) { if (!have_sticker_set_name(reply_sticker_set_id)) { queue.has_active_request_ = true; return send_request( - make_object(reply_sticker_set_id), + make_object(reply_sticker_set_id), td::make_unique(this, reply_sticker_set_id, user_id, 0, td::string(), 0)); } } @@ -13579,7 +13597,7 @@ void Client::process_new_business_callback_query_queue(int64 user_id) { if (!have_sticker_set_name(message_sticker_set_id)) { queue.has_active_request_ = true; return send_request( - make_object(message_sticker_set_id), + make_object(message_sticker_set_id), td::make_unique(this, message_sticker_set_id, 0, 0, td::string(), user_id)); } if (message_ref->reply_to_message_ != nullptr) { @@ -13588,7 +13606,7 @@ void Client::process_new_business_callback_query_queue(int64 user_id) { if (!have_sticker_set_name(reply_sticker_set_id)) { queue.has_active_request_ = true; return send_request( - make_object(reply_sticker_set_id), + make_object(reply_sticker_set_id), td::make_unique(this, reply_sticker_set_id, 0, 0, td::string(), user_id)); } } @@ -14163,7 +14181,7 @@ void Client::process_new_message_queue(int64 chat_id, int state) { if (!have_sticker_set_name(message_sticker_set_id)) { queue.has_active_request_ = true; return send_request( - make_object(message_sticker_set_id), + make_object(message_sticker_set_id), td::make_unique(this, message_sticker_set_id, 0, chat_id, td::string(), 0)); } if (reply_to_message_id > 0) { @@ -14173,7 +14191,7 @@ void Client::process_new_message_queue(int64 chat_id, int state) { if (!have_sticker_set_name(reply_sticker_set_id)) { queue.has_active_request_ = true; return send_request( - make_object(reply_sticker_set_id), + make_object(reply_sticker_set_id), td::make_unique(this, reply_sticker_set_id, 0, chat_id, td::string(), 0)); } } @@ -14263,7 +14281,7 @@ void Client::process_new_business_message_queue(const td::string &connection_id) if (!have_sticker_set_name(message_sticker_set_id)) { queue.has_active_request_ = true; return send_request( - make_object(message_sticker_set_id), + make_object(message_sticker_set_id), td::make_unique(this, message_sticker_set_id, 0, 0, connection_id, 0)); } if (message_ref->reply_to_message_ != nullptr) { @@ -14272,7 +14290,7 @@ void Client::process_new_business_message_queue(const td::string &connection_id) if (!have_sticker_set_name(reply_sticker_set_id)) { queue.has_active_request_ = true; return send_request( - make_object(reply_sticker_set_id), + make_object(reply_sticker_set_id), td::make_unique(this, reply_sticker_set_id, 0, 0, connection_id, 0)); } } @@ -14426,7 +14444,7 @@ void Client::init_message(MessageInfo *message_info, object_ptr auto sticker_set_id = get_sticker_set_id(message_info->content); if (!have_sticker_set_name(sticker_set_id)) { - send_request(make_object(sticker_set_id), + send_request(make_object(sticker_set_id), td::make_unique(this, sticker_set_id, 0, 0, td::string(), 0)); } } else if (message->content_->get_id() == td_api::messagePoll::ID) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index bc12bcb..5b430d9 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -266,7 +266,7 @@ class Client final : public WebhookActor::Callback { void on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, int64 new_message_chat_id, const td::string &new_message_business_connection_id, - int64 new_business_callback_query_user_id, object_ptr sticker_set); + int64 new_business_callback_query_user_id, object_ptr sticker_set_name); void on_get_sticker_set_name(int64 set_id, const td::string &name); From dfe0dc9881a4b55739026a38e832a80b625f756b Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 28 Aug 2024 12:01:43 +0300 Subject: [PATCH 153/162] Add Client::on_get_sticker_set_name overload. --- telegram-bot-api/Client.cpp | 22 ++++++++++------------ telegram-bot-api/Client.h | 2 ++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index cc3e12d..32fc2d4 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -5216,9 +5216,7 @@ class Client::TdOnGetChatCustomEmojiStickerSetCallback final : public TdQueryCal if (result->get_id() == td_api::error::ID) { supergroup_info->custom_emoji_sticker_set_id = 0; } else { - CHECK(result->get_id() == td_api::text::ID); - auto sticker_set_name = move_object_as(result); - client_->on_get_sticker_set_name(sticker_set_id_, sticker_set_name->text_); + client_->on_get_sticker_set_name(sticker_set_id_, std::move(result)); } answer_query(JsonChat(chat_id_, client_, true, pinned_message_id_), std::move(query_)); @@ -5254,9 +5252,7 @@ class Client::TdOnGetChatBusinessStartPageStickerSetCallback final : public TdQu user_info->business_info->start_page_->sticker_->set_id_ = 0; } } else { - CHECK(result->get_id() == td_api::text::ID); - auto sticker_set_name = move_object_as(result); - client_->on_get_sticker_set_name(sticker_set_id_, sticker_set_name->text_); + client_->on_get_sticker_set_name(sticker_set_id_, std::move(result)); } answer_query(JsonChat(chat_id_, client_, true, pinned_message_id_), std::move(query_)); @@ -5289,9 +5285,7 @@ class Client::TdOnGetChatStickerSetCallback final : public TdQueryCallback { if (result->get_id() == td_api::error::ID) { supergroup_info->sticker_set_id = 0; } else { - CHECK(result->get_id() == td_api::text::ID); - auto sticker_set_name = move_object_as(result); - client_->on_get_sticker_set_name(sticker_set_id_, sticker_set_name->text_); + client_->on_get_sticker_set_name(sticker_set_id_, std::move(result)); } auto sticker_set_id = supergroup_info->custom_emoji_sticker_set_id; @@ -5851,9 +5845,7 @@ class Client::TdOnGetStickerSetPromiseCallback final : public TdQueryCallback { return promise_.set_error(td::Status::Error(error->code_, error->message_)); } - CHECK(result->get_id() == td_api::text::ID); - auto sticker_set_name = move_object_as(result); - client_->on_get_sticker_set_name(sticker_set_id_, sticker_set_name->text_); + client_->on_get_sticker_set_name(sticker_set_id_, std::move(result)); promise_.set_value(td::Unit()); } @@ -6222,6 +6214,12 @@ void Client::on_get_sticker_set_name(int64 set_id, const td::string &name) { } } +void Client::on_get_sticker_set_name(int64 set_id, object_ptr sticker_set_name) { + CHECK(sticker_set_name->get_id() == td_api::text::ID); + auto text = move_object_as(sticker_set_name); + on_get_sticker_set_name(set_id, text->text_); +} + template void Client::check_user_read_access(const UserInfo *user_info, PromisedQueryPtr query, OnSuccess on_success) { CHECK(user_info != nullptr); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 5b430d9..820398b 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -270,6 +270,8 @@ class Client final : public WebhookActor::Callback { void on_get_sticker_set_name(int64 set_id, const td::string &name); + void on_get_sticker_set_name(int64 set_id, object_ptr sticker_set_name); + class TdQueryCallback { public: virtual void on_result(object_ptr result) = 0; From f8c757d07d30898ecc2f04e99cb0a14fdfbbb6aa Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 28 Aug 2024 12:10:37 +0300 Subject: [PATCH 154/162] Add TransactionPartnerUser.paid_media_payload. --- 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 32fc2d4..169672f 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4148,6 +4148,9 @@ class Client::JsonStarTransactionPartner final : public td::Jsonable { object("paid_media", td::json_array(purpose->media_, [client = client_](auto &media) { return JsonPaidMedia(media.get(), client); })); + if (!purpose->payload_.empty()) { + object("paid_media_payload", purpose->payload_); + } break; } default: From 3fdee61a88d92974d7d456ffdb5cdd9463557457 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 28 Aug 2024 12:13:10 +0300 Subject: [PATCH 155/162] Add sendPaidMedia.payload. --- 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 169672f..3db925d 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -10400,9 +10400,10 @@ td::Status Client::process_send_paid_media_query(PromisedQueryPtr &query) { int32 star_count = get_integer_arg(query.get(), "star_count", 0, 0, 1000000000); TRY_RESULT(paid_media, get_paid_media(query.get(), "media")); TRY_RESULT(caption, get_caption(query.get())); + auto payload = query->arg("payload").str(); auto show_caption_above_media = to_bool(query->arg("show_caption_above_media")); do_send_message(make_object(star_count, std::move(paid_media), std::move(caption), - show_caption_above_media, td::string()), + show_caption_above_media, payload), std::move(query)); return td::Status::OK(); } From 7422214945a17a3face29b3aa58cde7b05de7048 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 28 Aug 2024 12:27:23 +0300 Subject: [PATCH 156/162] Add GiveawayCreated.prize_star_count. --- telegram-bot-api/Client.cpp | 22 ++++++++++++++++++++-- telegram-bot-api/Client.h | 1 + 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 3db925d..468af8d 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2419,6 +2419,22 @@ class Client::JsonChatShared final : public td::Jsonable { const Client *client_; }; +class Client::JsonGiveawayCreated final : public td::Jsonable { + public: + explicit JsonGiveawayCreated(const td_api::messageGiveawayCreated *giveaway_created) + : giveaway_created_(giveaway_created) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + if (giveaway_created_->star_count_ > 0) { + object("prize_star_count", giveaway_created_->star_count_); + } + } + + private: + const td_api::messageGiveawayCreated *giveaway_created_; +}; + class Client::JsonGiveaway final : public td::Jsonable { public: JsonGiveaway(const td_api::messageGiveaway *giveaway, const Client *client) : giveaway_(giveaway), client_(client) { @@ -3290,9 +3306,11 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { } case td_api::messagePremiumGiftCode::ID: break; - case td_api::messageGiveawayCreated::ID: - object("giveaway_created", JsonEmptyObject()); + case td_api::messageGiveawayCreated::ID: { + auto content = static_cast(message_->content.get()); + object("giveaway_created", JsonGiveawayCreated(content)); break; + } case td_api::messageGiveaway::ID: { auto content = static_cast(message_->content.get()); object("giveaway", JsonGiveaway(content, client_)); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 820398b..dba71ac 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -194,6 +194,7 @@ class Client final : public WebhookActor::Callback { class JsonSharedUser; class JsonUsersShared; class JsonChatShared; + class JsonGiveawayCreated; class JsonGiveaway; class JsonGiveawayWinners; class JsonGiveawayCompleted; From 1548e96656b5214bcf6d98c5f0b6ed758d68977e Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 28 Aug 2024 12:29:44 +0300 Subject: [PATCH 157/162] Add Giveaway.prize_star_count. --- telegram-bot-api/Client.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 468af8d..c7c8db7 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2470,8 +2470,13 @@ class Client::JsonGiveaway final : public td::Jsonable { } break; } - case td_api::giveawayPrizeStars::ID: + case td_api::giveawayPrizeStars::ID: { + auto star_count = static_cast(giveaway_->prize_.get())->star_count_; + if (star_count > 0) { + object("prize_star_count", star_count); + } break; + } default: UNREACHABLE(); } From c08e6b3b84092111d4411761575c30c49714c1cb Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 28 Aug 2024 12:32:03 +0300 Subject: [PATCH 158/162] Add GiveawayWinners.prize_star_count. --- telegram-bot-api/Client.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index c7c8db7..676011d 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2515,8 +2515,13 @@ class Client::JsonGiveawayWinners final : public td::Jsonable { } break; } - case td_api::giveawayPrizeStars::ID: + case td_api::giveawayPrizeStars::ID: { + auto star_count = static_cast(giveaway_winners_->prize_.get())->star_count_; + if (star_count > 0) { + object("prize_star_count", star_count); + } break; + } default: UNREACHABLE(); } From cb41fe9930bb09cece032d26dc5659dbc7e47545 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 28 Aug 2024 13:13:51 +0300 Subject: [PATCH 159/162] Add "purchased_paid_media" update. --- telegram-bot-api/Client.cpp | 28 ++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 4 ++++ 2 files changed, 32 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 676011d..9542b2d 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3610,6 +3610,23 @@ class Client::JsonPreCheckoutQuery final : public td::Jsonable { const Client *client_; }; +class Client::JsonPaidMediaPurchased final : public td::Jsonable { + public: + JsonPaidMediaPurchased(const td_api::updatePaidMediaPurchased *update, const Client *client) + : update_(update), client_(client) { + } + + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("from", JsonUser(update_->user_id_, client_)); + object("payload", update_->payload_); + } + + private: + const td_api::updatePaidMediaPurchased *update_; + const Client *client_; +}; + class Client::JsonCustomJson final : public td::Jsonable { public: explicit JsonCustomJson(const td::string &json) : json_(json) { @@ -7252,6 +7269,9 @@ void Client::on_update(object_ptr result) { case td_api::updateNewPreCheckoutQuery::ID: add_new_pre_checkout_query(move_object_as(result)); break; + case td_api::updatePaidMediaPurchased::ID: + add_update_purchased_paid_media(move_object_as(result)); + break; case td_api::updateNewCustomEvent::ID: add_new_custom_event(move_object_as(result)); break; @@ -13349,6 +13369,8 @@ td::Slice Client::get_update_type_name(UpdateType update_type) { return td::Slice("edited_business_message"); case UpdateType::BusinessMessagesDeleted: return td::Slice("deleted_business_messages"); + case UpdateType::PurchasedPaidMedia: + return td::Slice("purchased_paid_media"); default: UNREACHABLE(); return td::Slice(); @@ -13672,6 +13694,12 @@ void Client::add_new_pre_checkout_query(object_ptrsender_user_id_ + (static_cast(4) << 33)); } +void Client::add_update_purchased_paid_media(object_ptr &&query) { + CHECK(query != nullptr); + add_update(UpdateType::PurchasedPaidMedia, JsonPaidMediaPurchased(query.get(), this), 86400, + query->user_id_ + (static_cast(12) << 33)); +} + void Client::add_new_custom_event(object_ptr &&event) { CHECK(event != nullptr); add_update(UpdateType::CustomEvent, JsonCustomJson(event->event_), 600, 0); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index dba71ac..24176c4 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -148,6 +148,7 @@ class Client final : public WebhookActor::Callback { class JsonInlineCallbackQuery; class JsonShippingQuery; class JsonPreCheckoutQuery; + class JsonPaidMediaPurchased; class JsonBotCommand; class JsonBotMenuButton; class JsonBotName; @@ -1108,6 +1109,8 @@ class Client final : public WebhookActor::Callback { void add_new_pre_checkout_query(object_ptr &&query); + void add_update_purchased_paid_media(object_ptr &&query); + void add_new_custom_event(object_ptr &&event); void add_new_custom_query(object_ptr &&query); @@ -1152,6 +1155,7 @@ class Client final : public WebhookActor::Callback { BusinessMessage, EditedBusinessMessage, BusinessMessagesDeleted, + PurchasedPaidMedia, Size }; From c96ab1328873fb1f9e0ddaed8d3c525a67b4246a Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 30 Aug 2024 11:44:17 +0300 Subject: [PATCH 160/162] Add ChatBoostSourceGiveaway.prize_star_count. --- 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 9542b2d..7748516 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3934,6 +3934,9 @@ class Client::JsonChatBoostSource final : public td::Jsonable { 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->star_count_ > 0) { + object("prize_star_count", source->star_count_); + } if (source->user_id_ != 0) { object("user", JsonUser(source->user_id_, client_)); } else if (source->is_unclaimed_) { From 4acd7d28e619d3f738adfe7c6b9d8ae097247b04 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 30 Aug 2024 11:45:49 +0300 Subject: [PATCH 161/162] Add GiveawayCompleted.is_star_giveaway. --- 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 7748516..6095f43 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2551,6 +2551,9 @@ class Client::JsonGiveawayCompleted final : public td::Jsonable { if (giveaway_completed_->unclaimed_prize_count_ > 0) { object("unclaimed_prize_count", giveaway_completed_->unclaimed_prize_count_); } + if (giveaway_completed_->is_star_giveaway_) { + object("is_star_giveaway", td::JsonTrue()); + } const MessageInfo *giveaway_message = client_->get_message(chat_id_, giveaway_completed_->giveaway_message_id_, true); if (giveaway_message != nullptr) { From a186a9ae823d91678ace87ef5b920688c555f5b5 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 6 Sep 2024 16:22:58 +0300 Subject: [PATCH 162/162] Update version to 7.10. --- 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 b5e56ca..74f1233 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 7.9 LANGUAGES CXX) +project(TelegramBotApi VERSION 7.10 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 9035a3b..a234ade 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.9"; + parameters->version_ = "7.10"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats();