From 6670225cc5bc6b1a91c76ecbe44289c2e2cb32d1 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 14 Jun 2026 00:27:11 +0300 Subject: Add and use Client::get_input_animation. --- telegram-bot-api/Client.cpp | 36 ++++++++++++++++++------------------ telegram-bot-api/Client.h | 4 ++++ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 068a505..ee90638 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -12184,6 +12184,19 @@ td::Result> Client::get_chat_permiss can_edit_tag, can_change_info, can_invite_users, can_pin_messages, can_manage_topics); } +td::Result> Client::get_input_animation( + const td::JsonObject &object, object_ptr &&input_file, + object_ptr &&input_thumbnail) { + 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")); + width = td::clamp(width, 0, MAX_LENGTH); + height = td::clamp(height, 0, MAX_LENGTH); + duration = td::clamp(duration, 0, MAX_DURATION); + return make_object(std::move(input_file), std::move(input_thumbnail), td::vector(), + duration, width, height); +} + td::Result> Client::get_input_checklist_task( td::JsonValue &&input_task) const { if (input_task.type() != td::JsonValue::Type::Object) { @@ -12326,16 +12339,9 @@ td::Result> Client::get_input_me 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")); - width = td::clamp(width, 0, MAX_LENGTH); - height = td::clamp(height, 0, MAX_LENGTH); - duration = td::clamp(duration, 0, MAX_DURATION); - return make_object( - make_object(std::move(input_file), std::move(input_thumbnail), td::vector(), - duration, width, height), - std::move(caption), show_caption_above_media, has_spoiler); + TRY_RESULT(input_animation, get_input_animation(object, std::move(input_file), std::move(input_thumbnail))); + return make_object(std::move(input_animation), std::move(caption), + show_caption_above_media, has_spoiler); } if (type == "audio") { TRY_RESULT(duration, object.get_optional_int_field("duration")); @@ -12442,14 +12448,8 @@ td::Result> Client::get_input_poll_me duration, width, height, supports_streaming)); } if (type == "animation") { - 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")); - width = td::clamp(width, 0, MAX_LENGTH); - height = td::clamp(height, 0, MAX_LENGTH); - duration = td::clamp(duration, 0, MAX_DURATION); - return make_object(make_object( - std::move(input_file), std::move(input_thumbnail), td::vector(), duration, width, height)); + TRY_RESULT(input_animation, get_input_animation(object, std::move(input_file), std::move(input_thumbnail))); + return make_object(std::move(input_animation)); } if (for_option ? type != "sticker" : type != "audio" && type != "document") { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index bf60e99..5f74874 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -673,6 +673,10 @@ class Client final : public WebhookActor::Callback { static td::Result> get_chat_permissions(const Query *query, bool &allow_legacy, bool use_independent_chat_permissions); + static td::Result> get_input_animation( + const td::JsonObject &object, object_ptr &&input_file, + object_ptr &&input_thumbnail); + td::Result> get_input_checklist_task(td::JsonValue &&input_task) const; td::Result>> get_input_checklist_tasks(td::JsonValue &&value) const; -- cgit v1.2.3 From 5acfd9f076b2b369f06176fb3e9da393cef29653 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 14 Jun 2026 00:31:50 +0300 Subject: Add and use Client::get_input_audio. --- telegram-bot-api/Client.cpp | 27 ++++++++++++++------------- telegram-bot-api/Client.h | 4 ++++ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index ee90638..c761fe3 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -12197,6 +12197,16 @@ td::Result> Client::get_input_animati duration, width, height); } +td::Result> Client::get_input_audio( + const td::JsonObject &object, object_ptr &&input_file, + object_ptr &&input_thumbnail) { + TRY_RESULT(duration, object.get_optional_int_field("duration")); + TRY_RESULT(title, object.get_optional_string_field("title")); + TRY_RESULT(performer, object.get_optional_string_field("performer")); + duration = td::clamp(duration, 0, MAX_DURATION); + return make_object(std::move(input_file), std::move(input_thumbnail), duration, title, performer); +} + td::Result> Client::get_input_checklist_task( td::JsonValue &&input_task) const { if (input_task.type() != td::JsonValue::Type::Object) { @@ -12344,13 +12354,8 @@ td::Result> Client::get_input_me show_caption_above_media, has_spoiler); } if (type == "audio") { - TRY_RESULT(duration, object.get_optional_int_field("duration")); - TRY_RESULT(title, object.get_optional_string_field("title")); - TRY_RESULT(performer, object.get_optional_string_field("performer")); - duration = td::clamp(duration, 0, MAX_DURATION); - return make_object( - make_object(std::move(input_file), std::move(input_thumbnail), duration, title, performer), - std::move(caption)); + TRY_RESULT(input_audio, get_input_audio(object, std::move(input_file), std::move(input_thumbnail))); + return make_object(std::move(input_audio), std::move(caption)); } if (type == "document") { TRY_RESULT(disable_content_type_detection, object.get_optional_bool_field("disable_content_type_detection")); @@ -12459,12 +12464,8 @@ td::Result> Client::get_input_poll_me return make_object(std::move(input_file), std::move(input_thumbnail), 0, 0); } if (type == "audio") { - TRY_RESULT(duration, object.get_optional_int_field("duration")); - TRY_RESULT(title, object.get_optional_string_field("title")); - TRY_RESULT(performer, object.get_optional_string_field("performer")); - duration = td::clamp(duration, 0, MAX_DURATION); - return make_object( - make_object(std::move(input_file), std::move(input_thumbnail), duration, title, performer)); + TRY_RESULT(input_audio, get_input_audio(object, std::move(input_file), std::move(input_thumbnail))); + return make_object(std::move(input_audio)); } if (type == "document") { TRY_RESULT(disable_content_type_detection, object.get_optional_bool_field("disable_content_type_detection")); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 5f74874..76393f7 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -677,6 +677,10 @@ class Client final : public WebhookActor::Callback { const td::JsonObject &object, object_ptr &&input_file, object_ptr &&input_thumbnail); + static td::Result> get_input_audio( + const td::JsonObject &object, object_ptr &&input_file, + object_ptr &&input_thumbnail); + td::Result> get_input_checklist_task(td::JsonValue &&input_task) const; td::Result>> get_input_checklist_tasks(td::JsonValue &&value) const; -- cgit v1.2.3 From 95c86a3090897e8391af5285f9906d76486dae5c Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 14 Jun 2026 00:38:39 +0300 Subject: Add and use Client::get_input_video. --- telegram-bot-api/Client.cpp | 56 +++++++++++++++++++-------------------------- telegram-bot-api/Client.h | 4 ++++ 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index c761fe3..d3a57cc 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -12207,6 +12207,25 @@ td::Result> Client::get_input_audio( return make_object(std::move(input_file), std::move(input_thumbnail), duration, title, performer); } +td::Result> Client::get_input_video( + const Query *query, const td::JsonObject &object, object_ptr &&input_file, + object_ptr &&input_thumbnail) const { + 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")); + TRY_RESULT(cover, object.get_optional_string_field("cover")); + TRY_RESULT(start_timestamp, object.get_optional_int_field("start_timestamp")); + TRY_RESULT(supports_streaming, object.get_optional_bool_field("supports_streaming")); + auto input_cover = get_input_file(query, td::Slice(), cover, false); + width = td::clamp(width, 0, MAX_LENGTH); + height = td::clamp(height, 0, MAX_LENGTH); + duration = td::clamp(duration, 0, MAX_DURATION); + start_timestamp = td::clamp(start_timestamp, 0, MAX_DURATION); + return make_object(std::move(input_file), std::move(input_thumbnail), std::move(input_cover), + start_timestamp, td::vector(), duration, width, height, + supports_streaming); +} + td::Result> Client::get_input_checklist_task( td::JsonValue &&input_task) const { if (input_task.type() != td::JsonValue::Type::Object) { @@ -12327,23 +12346,9 @@ td::Result> Client::get_input_me std::move(caption), show_caption_above_media, nullptr, has_spoiler); } if (type == "video") { - 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")); - TRY_RESULT(cover, object.get_optional_string_field("cover")); - TRY_RESULT(start_timestamp, object.get_optional_int_field("start_timestamp")); - TRY_RESULT(supports_streaming, object.get_optional_bool_field("supports_streaming")); - auto input_cover = get_input_file(query, td::Slice(), cover, false); - width = td::clamp(width, 0, MAX_LENGTH); - height = td::clamp(height, 0, MAX_LENGTH); - duration = td::clamp(duration, 0, MAX_DURATION); - start_timestamp = td::clamp(start_timestamp, 0, MAX_DURATION); - - return make_object( - make_object(std::move(input_file), std::move(input_thumbnail), std::move(input_cover), - start_timestamp, td::vector(), duration, width, height, - supports_streaming), - std::move(caption), show_caption_above_media, nullptr, has_spoiler); + TRY_RESULT(input_video, get_input_video(query, object, std::move(input_file), std::move(input_thumbnail))); + return make_object(std::move(input_video), std::move(caption), show_caption_above_media, + nullptr, has_spoiler); } if (type == "animation") { if (for_album) { @@ -12436,21 +12441,8 @@ td::Result> Client::get_input_poll_me std::move(input_photo), nullptr, std::move(input_file), td::vector(), 0, 0)); } if (type == "video") { - 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")); - TRY_RESULT(cover, object.get_optional_string_field("cover")); - TRY_RESULT(start_timestamp, object.get_optional_int_field("start_timestamp")); - TRY_RESULT(supports_streaming, object.get_optional_bool_field("supports_streaming")); - auto input_cover = get_input_file(query, td::Slice(), cover, false); - width = td::clamp(width, 0, MAX_LENGTH); - height = td::clamp(height, 0, MAX_LENGTH); - duration = td::clamp(duration, 0, MAX_DURATION); - start_timestamp = td::clamp(start_timestamp, 0, MAX_DURATION); - - return make_object(make_object( - std::move(input_file), std::move(input_thumbnail), std::move(input_cover), start_timestamp, td::vector(), - duration, width, height, supports_streaming)); + TRY_RESULT(input_video, get_input_video(query, object, std::move(input_file), std::move(input_thumbnail))); + return make_object(std::move(input_video)); } if (type == "animation") { TRY_RESULT(input_animation, get_input_animation(object, std::move(input_file), std::move(input_thumbnail))); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 76393f7..84352ab 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -681,6 +681,10 @@ class Client final : public WebhookActor::Callback { const td::JsonObject &object, object_ptr &&input_file, object_ptr &&input_thumbnail); + td::Result> get_input_video( + const Query *query, const td::JsonObject &object, object_ptr &&input_file, + object_ptr &&input_thumbnail) const; + td::Result> get_input_checklist_task(td::JsonValue &&input_task) const; td::Result>> get_input_checklist_tasks(td::JsonValue &&value) const; -- cgit v1.2.3 From 4834b964b3966f5c148f3f6980fab5c48df30f2e Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 14 Jun 2026 00:44:41 +0300 Subject: Add and use Client::get_input_photo. --- telegram-bot-api/Client.cpp | 50 +++++++++++++++++++++------------------------ telegram-bot-api/Client.h | 4 ++++ 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index d3a57cc..475166c 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -12207,6 +12207,22 @@ td::Result> Client::get_input_audio( return make_object(std::move(input_file), std::move(input_thumbnail), duration, title, performer); } +td::Result> Client::get_input_photo(const Query *query, + const td::JsonObject &object, + object_ptr &&input_file, + bool is_live) const { + if (is_live) { + TRY_RESULT(photo, object.get_optional_string_field("photo")); + auto input_photo = get_input_file(query, td::Slice(), photo, false); + if (input_photo == nullptr) { + return td::Status::Error("photo not found"); + } + return make_object(std::move(input_photo), nullptr, std::move(input_file), td::vector(), + 0, 0); + } + return make_object(std::move(input_file), nullptr, nullptr, td::vector(), 0, 0); +} + td::Result> Client::get_input_video( const Query *query, const td::JsonObject &object, object_ptr &&input_file, object_ptr &&input_thumbnail) const { @@ -12329,21 +12345,10 @@ td::Result> Client::get_input_me } TRY_RESULT(input_thumbnail, get_input_thumbnail(query, object, true)); - if (type == "photo") { - return make_object( - make_object(std::move(input_file), nullptr, nullptr, td::vector(), 0, 0), - std::move(caption), show_caption_above_media, nullptr, has_spoiler); - } - if (type == "live_photo") { - TRY_RESULT(photo, object.get_optional_string_field("photo")); - auto input_photo = get_input_file(query, td::Slice(), photo, false); - if (input_photo == nullptr) { - return td::Status::Error("photo not found"); - } - return make_object( - make_object(std::move(input_photo), nullptr, std::move(input_file), td::vector(), 0, - 0), - std::move(caption), show_caption_above_media, nullptr, has_spoiler); + if (type == "photo" || type == "live_photo") { + TRY_RESULT(input_photo, get_input_photo(query, object, std::move(input_file), type == "live_photo")); + return make_object(std::move(input_photo), std::move(caption), show_caption_above_media, + nullptr, has_spoiler); } if (type == "video") { TRY_RESULT(input_video, get_input_video(query, object, std::move(input_file), std::move(input_thumbnail))); @@ -12427,18 +12432,9 @@ td::Result> Client::get_input_poll_me } TRY_RESULT(input_thumbnail, get_input_thumbnail(query, object, true)); - if (type == "photo") { - return make_object( - make_object(std::move(input_file), nullptr, nullptr, td::vector(), 0, 0)); - } - if (type == "live_photo") { - TRY_RESULT(photo, object.get_optional_string_field("photo")); - auto input_photo = get_input_file(query, td::Slice(), photo, false); - if (input_photo == nullptr) { - return td::Status::Error("photo not found"); - } - return make_object(make_object( - std::move(input_photo), nullptr, std::move(input_file), td::vector(), 0, 0)); + if (type == "photo" || type == "live_photo") { + TRY_RESULT(input_photo, get_input_photo(query, object, std::move(input_file), type == "live_photo")); + return make_object(std::move(input_photo)); } if (type == "video") { TRY_RESULT(input_video, get_input_video(query, object, std::move(input_file), std::move(input_thumbnail))); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 84352ab..e03e559 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -681,6 +681,10 @@ class Client final : public WebhookActor::Callback { const td::JsonObject &object, object_ptr &&input_file, object_ptr &&input_thumbnail); + td::Result> get_input_photo(const Query *query, const td::JsonObject &object, + object_ptr &&input_file, + bool is_live) const; + td::Result> get_input_video( const Query *query, const td::JsonObject &object, object_ptr &&input_file, object_ptr &&input_thumbnail) const; -- cgit v1.2.3 From 09bc3f1c2753fdb0286c52377145464bdeb9a3a1 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 21 Jun 2026 00:27:29 +0300 Subject: Remove redundant checks. --- telegram-bot-api/Client.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 475166c..fb9d25b 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -14488,15 +14488,6 @@ td::Status Client::process_edit_message_reply_markup_query(PromisedQueryPtr &que td::Status Client::process_delete_message_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); auto message_id = get_message_id(query.get()); - - if (chat_id.empty()) { - return td::Status::Error(400, "Chat identifier is not specified"); - } - - if (message_id == 0) { - return td::Status::Error(400, "Message identifier is not specified"); - } - check_message(chat_id, message_id, false, AccessRights::Write, "message to delete", std::move(query), [this](int64 chat_id, int64 message_id, PromisedQueryPtr query) { send_request(make_object(chat_id, td::vector{message_id}, true), @@ -14508,9 +14499,6 @@ td::Status Client::process_delete_message_query(PromisedQueryPtr &query) { 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), -- cgit v1.2.3 From 9990031be959ebcdb1963e2a89119f0828f542a3 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 24 Jun 2026 10:33:12 +0300 Subject: Improve JsonChat. --- telegram-bot-api/Client.cpp | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index fb9d25b..41ba05b 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1588,19 +1588,25 @@ class Client::JsonChat final : public td::Jsonable { if (user_info->paid_message_star_count > 0) { object("paid_message_star_count", user_info->paid_message_star_count); } + photo = user_info->photo.get(); } - photo = user_info->photo.get(); break; } case ChatInfo::Type::Group: { object("title", chat_info->title); object("type", "group"); - const auto *permissions = chat_info->permissions.get(); - - auto group_info = client_->get_group_info(chat_info->group_id); - CHECK(group_info != nullptr); + auto everyone_is_administrator = + 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_link_previews_ && + permissions->can_react_to_messages_ && permissions->can_edit_tag_ && permissions->can_change_info_ && + permissions->can_invite_users_ && permissions->can_pin_messages_; + object("all_members_are_administrators", td::JsonBool(everyone_is_administrator)); if (is_full_) { + auto group_info = client_->get_group_info(chat_info->group_id); + CHECK(group_info != nullptr); if (!group_info->description.empty()) { object("description", group_info->description); } @@ -1608,17 +1614,9 @@ class Client::JsonChat final : public td::Jsonable { object("invite_link", group_info->invite_link); } object("permissions", JsonChatPermissions(permissions)); + object("accepted_gift_types", JsonAcceptedGiftTypes(false, false, false, false, false)); + photo = group_info->photo.get(); } - auto everyone_is_administrator = - 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_link_previews_ && - permissions->can_react_to_messages_ && permissions->can_edit_tag_ && permissions->can_change_info_ && - permissions->can_invite_users_ && permissions->can_pin_messages_; - object("all_members_are_administrators", td::JsonBool(everyone_is_administrator)); - object("accepted_gift_types", JsonAcceptedGiftTypes(false, false, false, false, false)); - photo = group_info->photo.get(); break; } case ChatInfo::Type::Supergroup: { @@ -1718,8 +1716,8 @@ class Client::JsonChat final : public td::Jsonable { if (supergroup_info->paid_message_star_count) { object("paid_message_star_count", supergroup_info->paid_message_star_count); } + photo = supergroup_info->photo.get(); } - photo = supergroup_info->photo.get(); break; } case ChatInfo::Type::Unknown: -- cgit v1.2.3 From 1446635ecb5c3084cfcc7a34425221177cfb3221 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 3 Jul 2026 10:56:35 +0300 Subject: Update TDLib to 1.8.66. --- td | 2 +- telegram-bot-api/Client.cpp | 126 +++++++++++++++++++++++--------------------- telegram-bot-api/Client.h | 10 ++-- 3 files changed, 73 insertions(+), 65 deletions(-) diff --git a/td b/td index a8f21f5..a9966eb 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit a8f21f5230172634becc1739050ef23ecd6ea291 +Subproject commit a9966eb3704a3351568c28013fed67d797c17828 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 41ba05b..fe8277c 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -684,8 +684,8 @@ class Client::JsonRichText final : public td::Jsonable { *scope << td::JsonString(text->text_); return; } - if (text_id == td_api::richTextIcon::ID) { - LOG(ERROR) << "Receive richTextIcon"; + if (text_id == td_api::richTextIcon::ID || text_id == td_api::richTextDiff::ID) { + LOG(ERROR) << "Receive " << to_string(*text_); *scope << td::JsonString(td::Slice()); return; } @@ -2002,11 +2002,10 @@ class Client::JsonSuggestedPostPrice final : public td::Jsonable { object("currency", "XTR"); object("amount", static_cast(suggested_post_price_)->star_count_); break; - case td_api::suggestedPostPriceTon::ID: + case td_api::suggestedPostPriceGram::ID: object("currency", "TON"); - object( - "amount", - static_cast(suggested_post_price_)->toncoin_cent_count_ * 10000000); + object("amount", + static_cast(suggested_post_price_)->gram_cent_count_ * 10000000); break; default: UNREACHABLE(); @@ -3065,7 +3064,7 @@ class Client::JsonSuggestedPostPaid final : public td::Jsonable { object("star_amount", JsonStarAmount(suggested_post_paid_->star_amount_.get())); } else { object("currency", "TON"); - object("amount", suggested_post_paid_->ton_amount_); + object("amount", suggested_post_paid_->gram_amount_); } } @@ -3532,10 +3531,10 @@ class Client::JsonUniqueGiftMessage final : public td::Jsonable { object("last_resale_amount", price->star_count_); break; } - case td_api::giftResalePriceTon::ID: { - auto price = static_cast(origin->price_.get()); + case td_api::giftResalePriceGram::ID: { + auto price = static_cast(origin->price_.get()); object("last_resale_currency", "TON"); - object("last_resale_amount", price->toncoin_cent_count_ * 10000000); + object("last_resale_amount", price->gram_cent_count_ * 10000000); break; } default: @@ -4674,7 +4673,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("sender_business_bot", JsonUser(message_->sender_business_bot_user_id, client_)); } } - object("message_id", message_->is_scheduled ? 0 : as_client_message_id(message_->id)); + object("message_id", as_client_message_id_unchecked(message_->id)); if (message_->sender_user_id != 0) { object("from", JsonUser(message_->sender_user_id, client_)); } @@ -5283,6 +5282,10 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("rich_message", JsonRichMessage(content->message_.get(), client_)); break; } + case td_api::messageChatAddedToCommunity::ID: + break; + case td_api::messageChatRemovedFromCommunity::ID: + break; default: UNREACHABLE(); } @@ -10383,9 +10386,9 @@ td::Result> Client::get_suggested } if (currency == "TON") { if (amount % 10000000 != 0) { - return td::Status::Error(400, "Suggested post price must be divisible by 10000000 nanotoncoins"); + return td::Status::Error(400, "Suggested post price must be divisible by 10000000 nanograms"); } - return make_object(amount / 10000000); + return make_object(amount / 10000000); } return td::Status::Error(400, "Invalid suggested post price currency specified"); } @@ -11105,7 +11108,7 @@ td::Result> Client::get_inlin TRY_RESULT(sticker_file_id, object.get_required_string_field("sticker_file_id")); if (input_message_content == nullptr) { - input_message_content = make_object(nullptr, nullptr, 0, 0, td::string()); + input_message_content = make_object(nullptr, td::string()); } return make_object(id, "", sticker_file_id, 0, 0, std::move(reply_markup), std::move(input_message_content)); @@ -11152,8 +11155,7 @@ td::Result> Client::get_inlin } if (input_message_content == nullptr) { - input_message_content = make_object( - nullptr, voice_note_duration, "" /* waveform */, std::move(caption), nullptr); + input_message_content = make_object(nullptr, std::move(caption), nullptr); } return make_object( id, title, voice_note_url, voice_note_duration, std::move(reply_markup), std::move(input_message_content)); @@ -11235,7 +11237,7 @@ td::Result> Client::get_bot_command(td::J TRY_RESULT(command, object.get_required_string_field("command")); TRY_RESULT(description, object.get_required_string_field("description")); - return make_object(command, description); + return make_object(command, description, false); } td::Result>> Client::get_bot_commands(const Query *query) { @@ -11502,9 +11504,8 @@ td::Result> Client::get_sticker_format return td::Status::Error(400, "Invalid sticker format specified"); } -td::Result> Client::get_input_sticker(const Query *query, - td::JsonValue &&value, - td::Slice default_sticker_format) const { +td::Result> Client::get_new_sticker(const Query *query, 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"); } @@ -11539,11 +11540,11 @@ td::Result> Client::get_input_sticker(c input_keywords.push_back(keyword.get_string().str()); } } - return make_object(std::move(input_file), std::move(sticker_format), 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 { +td::Result> Client::get_new_sticker(const Query *query) const { if (query->has_arg("sticker") || query->file("sticker") != nullptr) { auto sticker = query->arg("sticker"); LOG(INFO) << "Parsing JSON object: " << sticker; @@ -11553,17 +11554,17 @@ 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"); + auto r_sticker = get_new_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()); } return r_sticker.move_as_ok(); } - return get_legacy_input_sticker(query); + return get_legacy_new_sticker(query); } -td::Result> Client::get_legacy_input_sticker(const Query *query) const { +td::Result> Client::get_legacy_new_sticker(const Query *query) const { auto emojis = query->arg("emojis"); auto sticker = get_input_file(query, "png_sticker"); object_ptr sticker_format; @@ -11591,11 +11592,11 @@ td::Result> Client::get_legacy_input_st } } - return make_object(std::move(sticker), std::move(sticker_format), 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) const { +td::Result>> Client::get_new_stickers(const Query *query) const { if (query->has_arg("stickers")) { auto sticker_format_str = query->arg("sticker_format"); auto stickers = query->arg("stickers"); @@ -11616,21 +11617,21 @@ td::Result>> Client::get_inp return td::Status::Error(400, "Too many stickers specified"); } - td::vector> input_stickers; - for (auto &input_sticker : value.get_array()) { - 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()); + td::vector> new_stickers; + for (auto &new_sticker : value.get_array()) { + auto r_new_sticker = get_new_sticker(query, std::move(new_sticker), sticker_format_str); + if (r_new_sticker.is_error()) { + return td::Status::Error(400, PSLICE() << "Can't parse InputSticker: " << r_new_sticker.error().message()); } - input_stickers.push_back(r_input_sticker.move_as_ok()); + new_stickers.push_back(r_new_sticker.move_as_ok()); } - return std::move(input_stickers); + return std::move(new_stickers); } - TRY_RESULT(input_sticker, get_legacy_input_sticker(query)); + TRY_RESULT(new_sticker, get_legacy_new_sticker(query)); - td::vector> stickers; - stickers.push_back(std::move(input_sticker)); + td::vector> stickers; + stickers.push_back(std::move(new_sticker)); return std::move(stickers); } @@ -11985,10 +11986,10 @@ td::Result> Client::get_input_rich_ auto result = make_object(nullptr, is_rtl, !skip_entity_detection); if (object.has_field("markdown")) { TRY_RESULT(text, object.get_required_string_field("markdown")); - result->source_ = make_object(text); + result->source_ = make_object(text, td::Auto()); } else if (object.has_field("html")) { TRY_RESULT(text, object.get_required_string_field("html")); - result->source_ = make_object(text); + result->source_ = make_object(text, td::Auto()); } else { return td::Status::Error(400, "Rich message must be non-empty"); } @@ -12447,7 +12448,8 @@ td::Result> Client::get_input_poll_me return td::Status::Error(PSLICE() << "type \"" << type << "\" is unsupported"); } if (type == "sticker") { - return make_object(std::move(input_file), std::move(input_thumbnail), 0, 0); + return make_object( + make_object(std::move(input_file), std::move(input_thumbnail), 0, 0)); } if (type == "audio") { TRY_RESULT(input_audio, get_input_audio(object, std::move(input_file), std::move(input_thumbnail))); @@ -13661,7 +13663,8 @@ td::Status Client::process_send_sticker_query(PromisedQueryPtr &query) { return td::Status::Error(400, "There is no sticker in the request"); } auto emoji = query->arg("emoji"); - do_send_message(make_object(std::move(sticker), nullptr, 0, 0, emoji.str()), + do_send_message(make_object( + make_object(std::move(sticker), nullptr, 0, 0), emoji.str()), std::move(query)); return td::Status::OK(); } @@ -13698,9 +13701,10 @@ 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, nullptr), - std::move(query)); + do_send_message( + make_object( + make_object(std::move(video_note), std::move(thumbnail), duration, length), nullptr), + std::move(query)); return td::Status::OK(); } @@ -13712,7 +13716,8 @@ 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), nullptr), + make_object( + make_object(std::move(voice_note), duration, ""), std::move(caption), nullptr), std::move(query)); return td::Status::OK(); } @@ -16224,7 +16229,7 @@ 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")); - TRY_RESULT(stickers, get_input_stickers(query.get())); + TRY_RESULT(stickers, get_new_stickers(query.get())); TRY_RESULT(sticker_type, get_sticker_type(query->arg("sticker_type"))); if (to_bool(query->arg("contains_masks"))) { @@ -16245,7 +16250,7 @@ td::Status Client::process_create_new_sticker_set_query(PromisedQueryPtr &query) td::Status Client::process_add_sticker_to_set_query(PromisedQueryPtr &query) { TRY_RESULT(user_id, get_user_id(query.get())); auto name = query->arg("name"); - TRY_RESULT(sticker, get_input_sticker(query.get())); + TRY_RESULT(sticker, get_new_sticker(query.get())); check_user(user_id, std::move(query), [this, user_id, name, sticker = std::move(sticker)](PromisedQueryPtr query) mutable { @@ -16259,7 +16264,7 @@ 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())); + TRY_RESULT(sticker, get_new_sticker(query.get())); check_user(user_id, std::move(query), [this, user_id, name, input_file = std::move(input_file), @@ -17862,11 +17867,12 @@ void Client::process_new_callback_query_queue(int64 user_id, int state) { CHECK(state == 3); CHECK(user_id == query->sender_user_id_); - add_update(UpdateType::CallbackQuery, - JsonCallbackQuery(query->id_, user_id, chat_id, message_id, message_info, query->chat_instance_, - query->payload_.get(), this), - 150, user_id + (static_cast(3) << 33)); - + if (message_info != nullptr || as_tdlib_message_id(as_client_message_id_unchecked(message_id)) == message_id) { + add_update(UpdateType::CallbackQuery, + JsonCallbackQuery(query->id_, user_id, chat_id, message_id, message_info, query->chat_instance_, + query->payload_.get(), this), + 150, user_id + (static_cast(3) << 33)); + } queue.queue_.pop(); state = 0; } @@ -18249,6 +18255,8 @@ bool Client::need_skip_update_message(int64 chat_id, const MessageInfo *message_ case td_api::messageUpgradedGiftPurchaseOfferRejected::ID: case td_api::messageChatHasProtectedContentToggled::ID: case td_api::messageChatHasProtectedContentDisableRequested::ID: + case td_api::messageChatAddedToCommunity::ID: + case td_api::messageChatRemovedFromCommunity::ID: return true; default: break; @@ -18388,9 +18396,9 @@ bool Client::are_equal_suggested_post_prices(const td_api::SuggestedPostPrice *l case td_api::suggestedPostPriceStar::ID: return static_cast(lhs)->star_count_ == static_cast(rhs)->star_count_; - case td_api::suggestedPostPriceTon::ID: - return static_cast(lhs)->toncoin_cent_count_ == - static_cast(rhs)->toncoin_cent_count_; + case td_api::suggestedPostPriceGram::ID: + return static_cast(lhs)->gram_cent_count_ == + static_cast(rhs)->gram_cent_count_; default: UNREACHABLE(); return false; @@ -18899,7 +18907,7 @@ td::unique_ptr Client::create_message(object_ptrsender_tag = std::move(message->sender_tag_); message_info->paid_message_star_count = message->paid_message_star_count_; message_info->effect_id = message->effect_id_; - message_info->is_paid_post = message->is_paid_star_suggested_post_ || message->is_paid_ton_suggested_post_; + message_info->is_paid_post = message->is_paid_star_suggested_post_ || message->is_paid_gram_suggested_post_; message_info->is_outgoing = message->is_outgoing_; message_info->is_self_destruct = message->self_destruct_type_ != nullptr; message_info->is_imported = message->import_info_ != nullptr; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index e03e559..5af30db 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -615,14 +615,14 @@ 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_legacy_new_sticker(const Query *query) const; - td::Result> get_input_sticker(const Query *query) const; + td::Result> get_new_sticker(const Query *query) const; - td::Result> get_input_sticker(const Query *query, td::JsonValue &&value, - td::Slice default_sticker_format) const; + td::Result> get_new_sticker(const Query *query, td::JsonValue &&value, + td::Slice default_sticker_format) const; - td::Result>> get_input_stickers(const Query *query) const; + td::Result>> get_new_stickers(const Query *query) const; static td::Result> get_sticker_input_file(const Query *query, td::Slice field_name = "sticker"); -- cgit v1.2.3 From 075eabd2fa0d033b5e163bcd0716c7f3a315b1e0 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 3 Jul 2026 11:00:27 +0300 Subject: Support ephemeral bot commands. --- telegram-bot-api/Client.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index fe8277c..7c3ccc9 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -5613,6 +5613,9 @@ class Client::JsonBotCommand final : public td::Jsonable { auto object = scope->enter_object(); object("command", command_->command_); object("description", command_->description_); + if (command_->is_ephemeral_) { + object("is_ephemeral", td::JsonTrue()); + } } private: @@ -11236,8 +11239,9 @@ td::Result> Client::get_bot_command(td::J TRY_RESULT(command, object.get_required_string_field("command")); TRY_RESULT(description, object.get_required_string_field("description")); + TRY_RESULT(is_ephemeral, object.get_optional_bool_field("is_ephemeral")); - return make_object(command, description, false); + return make_object(command, description, is_ephemeral); } td::Result>> Client::get_bot_commands(const Query *query) { -- cgit v1.2.3 From 797c19eacdc9842efe361b87606660a117ca95c8 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 3 Jul 2026 11:05:02 +0300 Subject: Add Message.receiver_user. --- 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 7c3ccc9..e55b2cc 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4692,6 +4692,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { if (forum_topic_id != 0) { object("message_thread_id", forum_topic_id); } + if (message_->receiver_id != nullptr) { + client_->json_store_message_sender(object, message_->receiver_id, "receiver_user", "receiver_chat"); + } if (message_->initial_send_date > 0) { CHECK(message_->forward_origin != nullptr); object("forward_origin", JsonMessageOrigin(message_->forward_origin.get(), message_->initial_send_date, client_)); @@ -18855,6 +18858,7 @@ td::unique_ptr Client::create_message(object_ptrchat_id_; message_info->id = message->id_; message_info->chat_id = chat_id; + message_info->receiver_id = std::move(message->receiver_id_); message_info->date = message->date_; message_info->edit_date = message->edit_date_; message_info->media_album_id = message->media_album_id_; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 5af30db..d28945c 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -1196,6 +1196,7 @@ class Client final : public WebhookActor::Callback { int64 sender_user_id = 0; int64 sender_chat_id = 0; int64 chat_id = 0; + object_ptr receiver_id; int32 date = 0; int32 edit_date = 0; int32 initial_send_date = 0; -- cgit v1.2.3 From 022e0c8fccdaf955588c8f7b3a109614fb693384 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 3 Jul 2026 11:12:57 +0300 Subject: Add Message.ephemeral_message_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 e55b2cc..73783d8 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4674,6 +4674,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { } } object("message_id", as_client_message_id_unchecked(message_->id)); + if (message_->ephemeral_message_id != 0) { + object("ephemeral_message_id", message_->ephemeral_message_id); + } if (message_->sender_user_id != 0) { object("from", JsonUser(message_->sender_user_id, client_)); } @@ -18859,6 +18862,7 @@ td::unique_ptr Client::create_message(object_ptrid = message->id_; message_info->chat_id = chat_id; message_info->receiver_id = std::move(message->receiver_id_); + message_info->ephemeral_message_id = message->ephemeral_message_id_; message_info->date = message->date_; message_info->edit_date = message->edit_date_; message_info->media_album_id = message->media_album_id_; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index d28945c..af0d323 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -1201,6 +1201,7 @@ class Client final : public WebhookActor::Callback { int32 edit_date = 0; int32 initial_send_date = 0; int32 sender_boost_count = 0; + int32 ephemeral_message_id = 0; int64 paid_message_star_count = 0; int64 guest_query_id = 0; object_ptr forward_origin; -- cgit v1.2.3 From 4e42df337e2d0457d035550a69724e28c3868e59 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 3 Jul 2026 11:20:46 +0300 Subject: Support sending of ephemeral messages. --- telegram-bot-api/Client.cpp | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 73783d8..70eb128 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -16843,6 +16843,15 @@ void Client::do_send_message(object_ptr input_messa auto chat_id = query->arg("chat_id"); auto forum_topic_id = get_forum_topic_id(query.get(), "message_thread_id"); auto business_connection_id = query->arg("business_connection_id"); + int64 receiver_user_id = 0; + if (query->has_arg("receiver_user_id")) { + auto r_receiver_user_id = get_user_id(query.get(), "receiver_user_id"); + if (r_receiver_user_id.is_error()) { + return fail_query_with_error(std::move(query), 400, r_receiver_user_id.error().message()); + } + receiver_user_id = r_receiver_user_id.move_as_ok(); + } + auto callback_query_id = td::to_integer(query->arg("callback_query_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()); @@ -16868,10 +16877,10 @@ 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(), forum_topic_id, direct_messages_topic_id, - business_connection_id = business_connection_id.str(), reply_parameters = std::move(reply_parameters), - disable_notification, protect_content, allow_paid_broadcast, effect_id, send_options = std::move(send_options), - input_message_content = std::move(input_message_content)](object_ptr reply_markup, - PromisedQueryPtr query) mutable { + business_connection_id = business_connection_id.str(), receiver_user_id, callback_query_id, + reply_parameters = std::move(reply_parameters), disable_notification, protect_content, allow_paid_broadcast, + effect_id, send_options = std::move(send_options), input_message_content = std::move(input_message_content)]( + object_ptr reply_markup, PromisedQueryPtr query) mutable { if (!business_connection_id.empty()) { return check_business_connection_chat_id( business_connection_id, chat_id_str, std::move(query), @@ -16887,7 +16896,7 @@ void Client::do_send_message(object_ptr input_messa }); } - auto on_success = [this, send_options = std::move(send_options), + auto on_success = [this, receiver_user_id, callback_query_id, send_options = std::move(send_options), input_message_content = std::move(input_message_content), reply_markup = std::move(reply_markup)]( int64 chat_id, object_ptr topic_id, @@ -16898,6 +16907,14 @@ void Client::do_send_message(object_ptr input_messa } count++; + if (receiver_user_id != 0) { + return send_request(make_object( + chat_id, std::move(topic_id), receiver_user_id, callback_query_id, + get_input_message_reply_to(std::move(reply_parameters)), 0, false, + std::move(reply_markup), std::move(input_message_content)), + td::make_unique(this, chat_id, std::move(query))); + } + send_request(make_object( chat_id, std::move(topic_id), get_input_message_reply_to(std::move(reply_parameters)), std::move(send_options), std::move(reply_markup), std::move(input_message_content)), -- cgit v1.2.3 From c4c11692450a39a81558ed8f47beae01e2156edb Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 3 Jul 2026 11:36:27 +0300 Subject: Support sending replies to ephemeral messages. --- telegram-bot-api/Client.cpp | 39 +++++++++++++++++++++++++-------------- telegram-bot-api/Client.h | 5 ++++- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 70eb128..3cc97af 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -9070,6 +9070,11 @@ void Client::check_reply_parameters(td::Slice chat_id_str, InputReplyParameters chat_id_str, forum_topic_id, direct_messages_topic_id, std::move(query), [this, reply_parameters = std::move(reply_parameters), on_success = std::move(on_success)]( int64 chat_id, object_ptr &&topic_id, PromisedQueryPtr query) mutable { + if (reply_parameters.reply_to_ephemeral_message_id > 0) { + CheckedReplyParameters checked_reply_parameters; + checked_reply_parameters.reply_to_ephemeral_message_id = reply_parameters.reply_to_ephemeral_message_id; + return on_success(chat_id, std::move(topic_id), std::move(checked_reply_parameters), std::move(query)); + } auto on_reply_message_resolved = [this, chat_id, topic_id = std::move(topic_id), quote = std::move(reply_parameters.quote), checklist_task_id = reply_parameters.checklist_task_id, @@ -9953,6 +9958,9 @@ 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_ephemeral_message_id > 0) { + return make_object(reply_parameters.reply_to_ephemeral_message_id); + } if (reply_parameters.reply_to_message_id > 0) { if (reply_parameters.reply_in_chat_id != 0) { return make_object( @@ -9966,7 +9974,7 @@ td_api::object_ptr Client::get_input_message_reply_ return nullptr; } -td_api::object_ptr Client::get_input_message_reply_to( +td_api::object_ptr Client::get_input_message_reply_to_unchecked( InputReplyParameters &&reply_parameters) { if (reply_parameters.reply_in_chat_id.empty() && reply_parameters.reply_to_message_id > 0) { return make_object( @@ -10008,7 +10016,7 @@ td::Result Client::get_reply_parameters(td::JsonVa 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(message_id, object.get_optional_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")); @@ -10017,10 +10025,12 @@ td::Result Client::get_reply_parameters(td::JsonVa TRY_RESULT(quote_position, object.get_optional_int_field("quote_position")); TRY_RESULT(checklist_task_id, object.get_optional_int_field("checklist_task_id")); TRY_RESULT(poll_option_id, object.get_optional_string_field("poll_option_id")); + TRY_RESULT(ephemeral_message_id, object.get_optional_int_field("ephemeral_message_id")); 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.reply_to_ephemeral_message_id = td::max(ephemeral_message_id, 0); result.allow_sending_without_reply = allow_sending_without_reply; result.quote = make_object(std::move(quote), quote_position); result.checklist_task_id = checklist_task_id; @@ -14094,12 +14104,12 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &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)), - disable_notification, protect_content, effect_id, std::move(input_message_contents)), - td::make_unique(this, business_connection->id_, - std::move(query))); + send_request(make_object( + business_connection->id_, chat_id, + get_input_message_reply_to_unchecked(std::move(reply_parameters)), + disable_notification, protect_content, effect_id, std::move(input_message_contents)), + td::make_unique(this, business_connection->id_, + std::move(query))); }); } @@ -16887,12 +16897,13 @@ void Client::do_send_message(object_ptr input_messa [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, - 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_unchecked(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 af0d323..7109aa1 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -352,6 +352,7 @@ class Client final : public WebhookActor::Callback { struct InputReplyParameters { td::string reply_in_chat_id; int64 reply_to_message_id = 0; + int32 reply_to_ephemeral_message_id = 0; bool allow_sending_without_reply = false; object_ptr quote; int32 checklist_task_id = 0; @@ -361,6 +362,7 @@ class Client final : public WebhookActor::Callback { struct CheckedReplyParameters { int64 reply_in_chat_id = 0; int64 reply_to_message_id = 0; + int32 reply_to_ephemeral_message_id = 0; object_ptr quote; int32 checklist_task_id = 0; td::string poll_option_id; @@ -499,7 +501,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 object_ptr get_input_message_reply_to_unchecked( + InputReplyParameters &&reply_parameters); static td::Result get_reply_parameters(const Query *query); -- cgit v1.2.3 From c7c85dfbb0c68df9ebd85b36410ef50990ee559c Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 3 Jul 2026 11:48:08 +0300 Subject: Add deleteEphemeralMessage. --- 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 3cc97af..71d1ff7 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -271,6 +271,7 @@ bool Client::init_methods() { 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("deleteephemeralmessage", &Client::process_delete_ephemeral_message_query); methods_.emplace("deletemessagereaction", &Client::process_delete_message_reaction_query); methods_.emplace("deleteallmessagereactions", &Client::process_delete_all_message_reactions_query); methods_.emplace("poststory", &Client::process_post_story_query); @@ -14530,6 +14531,19 @@ td::Status Client::process_delete_messages_query(PromisedQueryPtr &query) { return td::Status::OK(); } +td::Status Client::process_delete_ephemeral_message_query(PromisedQueryPtr &query) { + auto chat_id = query->arg("chat_id"); + TRY_RESULT(receiver_user_id, get_user_id(query.get(), "receiver_user_id")); + auto ephemeral_message_id = get_integer_arg(query.get(), "ephemeral_message_id", 0); + check_chat(chat_id, AccessRights::Read, std::move(query), + [this, receiver_user_id, ephemeral_message_id](int64 chat_id, PromisedQueryPtr query) { + send_request( + make_object(chat_id, receiver_user_id, ephemeral_message_id), + td::make_unique(std::move(query))); + }); + return td::Status::OK(); +} + td::Status Client::process_delete_message_reaction_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 7109aa1..bc7b1e7 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -862,6 +862,7 @@ class Client final : public WebhookActor::Callback { 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_delete_ephemeral_message_query(PromisedQueryPtr &query); td::Status process_delete_message_reaction_query(PromisedQueryPtr &query); td::Status process_delete_all_message_reactions_query(PromisedQueryPtr &query); td::Status process_post_story_query(PromisedQueryPtr &query); -- cgit v1.2.3 From c944357716b46be75ddbb96d840c00d571302b24 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 3 Jul 2026 12:04:45 +0300 Subject: Support rich messages in get_input_media. --- telegram-bot-api/Client.cpp | 24 +++++++++++++++++++++--- telegram-bot-api/Client.h | 5 ++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 71d1ff7..62f17db 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -12262,6 +12262,13 @@ td::Result> Client::get_input_video( supports_streaming); } +td::Result> Client::get_input_voice_note( + const td::JsonObject &object, object_ptr &&input_file) { + TRY_RESULT(duration, object.get_optional_int_field("duration")); + duration = td::clamp(duration, 0, MAX_DURATION); + return make_object(std::move(input_file), duration, td::string()); +} + td::Result> Client::get_input_checklist_task( td::JsonValue &&input_task) const { if (input_task.type() != td::JsonValue::Type::Object) { @@ -12350,13 +12357,14 @@ td::Result> Client::get_input_me TRY_RESULT(has_spoiler, object.get_optional_bool_field("has_spoiler")); TRY_RESULT(type, object.get_required_string_field("type")); - return get_input_media(query, object, type, std::move(caption), show_caption_above_media, has_spoiler, for_album); + return get_input_media(query, object, type, std::move(caption), show_caption_above_media, has_spoiler, for_album, + false); } td::Result> Client::get_input_media( const Query *query, const td::JsonObject &object, const td::string &type, - object_ptr &&caption, bool show_caption_above_media, bool has_spoiler, - bool for_album) const { + object_ptr &&caption, bool show_caption_above_media, bool has_spoiler, bool for_album, + bool for_rich_message) const { TRY_RESULT(media, object.get_optional_string_field("media")); auto input_file = get_input_file(query, td::Slice(), media, false); @@ -12388,12 +12396,22 @@ td::Result> Client::get_input_me return make_object(std::move(input_audio), std::move(caption)); } if (type == "document") { + if (for_rich_message) { + return td::Status::Error(PSLICE() << "type \"" << type << "\" is not allowed"); + } TRY_RESULT(disable_content_type_detection, object.get_optional_bool_field("disable_content_type_detection")); return make_object( make_object(std::move(input_file), std::move(input_thumbnail), disable_content_type_detection || for_album), std::move(caption)); } + if (type == "voice_note") { + if (!for_rich_message) { + return td::Status::Error(PSLICE() << "type \"" << type << "\" is not allowed"); + } + TRY_RESULT(input_voice_note, get_input_voice_note(object, std::move(input_file))); + return make_object(std::move(input_voice_note), std::move(caption), nullptr); + } return td::Status::Error(PSLICE() << "type \"" << type << "\" is unsupported"); } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index bc7b1e7..fe3dd5c 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -692,6 +692,9 @@ class Client final : public WebhookActor::Callback { const Query *query, const td::JsonObject &object, object_ptr &&input_file, object_ptr &&input_thumbnail) const; + static td::Result> get_input_voice_note( + const td::JsonObject &object, object_ptr &&input_file); + td::Result> get_input_checklist_task(td::JsonValue &&input_task) const; td::Result>> get_input_checklist_tasks(td::JsonValue &&value) const; @@ -708,7 +711,7 @@ class Client final : public WebhookActor::Callback { const td::string &type, object_ptr &&caption, bool show_caption_above_media, bool has_spoiler, - bool for_album) const; + bool for_album, bool for_rich_message) const; td::Result> get_input_media(const Query *query, td::Slice field_name) const; -- cgit v1.2.3 From 79e689906b793ff7a6280f5a251dd0680be46cdb Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 3 Jul 2026 17:49:57 +0300 Subject: Support td_api::inputRichMessageMedia. --- telegram-bot-api/Client.cpp | 33 +++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 6 ++++++ 2 files changed, 39 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 62f17db..a60967f 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -12524,6 +12524,39 @@ td::Result> Client::get_input_poll_me return r_input_message_content.move_as_ok(); } +td::Result> Client::get_input_rich_message_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(id, object.get_required_string_field("id")); + TRY_RESULT(media, object.extract_required_field("media", td::JsonValue::Type::Object)); + auto &media_object = media.get_object(); + TRY_RESULT(type, media_object.get_required_string_field("type")); + TRY_RESULT(input_message_content, get_input_media(query, media_object, type, nullptr, false, false, false, true)); + return make_object(id, std::move(input_message_content)); +} + +td::Result>> Client::get_input_rich_message_medias( + const Query *query, td::JsonValue &&value) const { + if (value.type() != td::JsonValue::Type::Array) { + return td::Status::Error(400, "Expected an Array of InputRichMessageMedia"); + } + + td::vector> media; + for (auto &input_media : value.get_array()) { + auto r_input_media = get_input_rich_message_media(query, std::move(input_media)); + if (r_input_media.is_error()) { + return td::Status::Error(400, PSLICE() + << "Can't parse InputRichMessageMedia: " << r_input_media.error().message()); + } + media.push_back(r_input_media.move_as_ok()); + } + return std::move(media); +} + td::Result>> Client::get_input_message_contents( const Query *query, td::Slice field_name) const { TRY_RESULT(media, get_required_string_arg(query, field_name)); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index fe3dd5c..a42a014 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -720,6 +720,12 @@ class Client final : public WebhookActor::Callback { td::Result> get_input_poll_media(const Query *query, td::Slice field_name) const; + td::Result> get_input_rich_message_media(const Query *query, + td::JsonValue &&input_media) const; + + td::Result>> get_input_rich_message_medias( + const Query *query, td::JsonValue &&value) const; + td::Result>> get_input_message_contents( const Query *query, td::Slice field_name) const; -- cgit v1.2.3 From 314068fbcc815e35a5a3a28b7538f4a615dc5c96 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 3 Jul 2026 18:18:37 +0300 Subject: Support media in InputRichMessage. --- telegram-bot-api/Client.cpp | 38 ++++++++++++++++++++++---------------- telegram-bot-api/Client.h | 26 ++++++++++++++------------ 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index a60967f..ce97bba 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -10695,13 +10695,13 @@ td::Result> Client::get_input_thumbna } td::Result> Client::get_input_message_content( - td::JsonValue &input_message_content, bool is_input_message_content_required) { + const Query *query, td::JsonValue &input_message_content, bool is_input_message_content_required) const { CHECK(input_message_content.type() == td::JsonValue::Type::Object); auto &object = input_message_content.get_object(); if (object.has_field("rich_message")) { TRY_RESULT(rich_message, object.extract_required_field("rich_message", td::JsonValue::Type::Object)); - TRY_RESULT(input_rich_message, get_input_rich_message(std::move(rich_message))); + TRY_RESULT(input_rich_message, get_input_rich_message(query, std::move(rich_message))); return make_object(std::move(input_rich_message), false); } @@ -10855,7 +10855,7 @@ td::Result> Client::get_inl } td::Result>> Client::get_inline_query_results( - const Query *query, BotUserIds &bot_user_ids) { + const Query *query, BotUserIds &bot_user_ids) const { auto results_encoded = query->arg("results"); if (results_encoded.empty()) { return td::vector>(); @@ -10868,11 +10868,11 @@ td::Result>> Clien 400, PSLICE() << "Can't parse JSON encoded inline query results: " << r_values.error().message()); } - return get_inline_query_results(r_values.move_as_ok(), bot_user_ids); + return get_inline_query_results(query, r_values.move_as_ok(), bot_user_ids); } td::Result>> Client::get_inline_query_results( - td::JsonValue &&values, BotUserIds &bot_user_ids) { + const Query *query, td::JsonValue &&values, BotUserIds &bot_user_ids) const { if (values.type() == td::JsonValue::Type::Null) { return td::vector>(); } @@ -10886,7 +10886,7 @@ td::Result>> Clien td::vector> inline_query_results; for (auto &value : values.get_array()) { - auto r_inline_query_result = get_inline_query_result(std::move(value), bot_user_ids); + auto r_inline_query_result = get_inline_query_result(query, std::move(value), bot_user_ids); if (r_inline_query_result.is_error()) { return td::Status::Error( 400, PSLICE() << "Can't parse inline query result: " << r_inline_query_result.error().message()); @@ -10898,7 +10898,7 @@ td::Result>> Clien } td::Result> Client::get_inline_query_result( - const Query *query, BotUserIds &bot_user_ids) { + const Query *query, BotUserIds &bot_user_ids) const { auto result_encoded = query->arg("result"); if (result_encoded.empty()) { return td::Status::Error(400, "Result isn't specified"); @@ -10911,11 +10911,11 @@ td::Result> Client::get_inlin 400, PSLICE() << "Can't parse JSON encoded web view query results " << r_value.error().message()); } - return get_inline_query_result(r_value.move_as_ok(), bot_user_ids); + return get_inline_query_result(query, r_value.move_as_ok(), bot_user_ids); } td::Result> Client::get_inline_query_result( - td::JsonValue &&value, BotUserIds &bot_user_ids) { + const Query *query, td::JsonValue &&value, BotUserIds &bot_user_ids) const { if (value.type() != td::JsonValue::Type::Object) { return td::Status::Error(400, "Inline query result must be an object"); } @@ -10948,7 +10948,7 @@ td::Result> Client::get_inlin } } else { TRY_RESULT(input_message_content_result, - get_input_message_content(input_message_content_obj, is_input_message_content_required)); + get_input_message_content(query, input_message_content_obj, is_input_message_content_required)); input_message_content = std::move(input_message_content_result); } TRY_RESULT(input_caption, object.get_optional_string_field("caption")); @@ -11981,7 +11981,7 @@ td::Result> Client::get_input_messa return make_object(std::move(formatted_text), std::move(link_preview_options), false); } -td::Result> Client::get_input_rich_message(const Query *query) { +td::Result> Client::get_input_rich_message(const Query *query) const { auto rich_message = query->arg("rich_message"); if (rich_message.empty()) { return td::Status::Error(400, "Rich message must be non-empty"); @@ -11994,10 +11994,11 @@ td::Result> Client::get_input_rich_ return td::Status::Error(400, "Can't parse rich message JSON object"); } - return get_input_rich_message(r_value.move_as_ok()); + return get_input_rich_message(query, r_value.move_as_ok()); } -td::Result> Client::get_input_rich_message(td::JsonValue &&value) { +td::Result> Client::get_input_rich_message(const Query *query, + td::JsonValue &&value) const { if (value.type() != td::JsonValue::Type::Object) { return td::Status::Error(400, "Object expected as rich message"); } @@ -12007,10 +12008,12 @@ td::Result> Client::get_input_rich_ auto result = make_object(nullptr, is_rtl, !skip_entity_detection); if (object.has_field("markdown")) { TRY_RESULT(text, object.get_required_string_field("markdown")); - result->source_ = make_object(text, td::Auto()); + TRY_RESULT(media, get_input_rich_message_medias(query, object.extract_field("media"))); + result->source_ = make_object(text, std::move(media)); } else if (object.has_field("html")) { TRY_RESULT(text, object.get_required_string_field("html")); - result->source_ = make_object(text, td::Auto()); + TRY_RESULT(media, get_input_rich_message_medias(query, object.extract_field("media"))); + result->source_ = make_object(text, std::move(media)); } else { return td::Status::Error(400, "Rich message must be non-empty"); } @@ -12541,11 +12544,14 @@ td::Result> Client::get_input_ td::Result>> Client::get_input_rich_message_medias( const Query *query, td::JsonValue &&value) const { + td::vector> media; if (value.type() != td::JsonValue::Type::Array) { + if (value.type() == td::JsonValue::Type::Null) { + return std::move(media); + } return td::Status::Error(400, "Expected an Array of InputRichMessageMedia"); } - td::vector> media; for (auto &input_media : value.get_array()) { auto r_input_media = get_input_rich_message_media(query, std::move(input_media)); if (r_input_media.is_error()) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index a42a014..d95a03e 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -542,8 +542,8 @@ class Client final : public WebhookActor::Callback { static td::Result>> get_shipping_options(td::JsonValue &&value); - static td::Result> get_input_message_content( - td::JsonValue &input_message_content, bool is_input_message_content_required); + td::Result> get_input_message_content( + const Query *query, td::JsonValue &input_message_content, bool is_input_message_content_required) const; static object_ptr get_chat_action(const Query *query); @@ -565,17 +565,18 @@ class Client final : public WebhookActor::Callback { static td::Result> get_inline_query_results_button( td::MutableSlice value); - static td::Result> get_inline_query_result(const Query *query, - BotUserIds &bot_user_ids); + td::Result> get_inline_query_result(const Query *query, + BotUserIds &bot_user_ids) const; - static td::Result> get_inline_query_result(td::JsonValue &&value, - BotUserIds &bot_user_ids); + td::Result> get_inline_query_result(const Query *query, + td::JsonValue &&value, + BotUserIds &bot_user_ids) const; - static td::Result>> get_inline_query_results( - const Query *query, BotUserIds &bot_user_ids); + td::Result>> get_inline_query_results( + const Query *query, BotUserIds &bot_user_ids) const; - static td::Result>> get_inline_query_results( - td::JsonValue &&value, BotUserIds &bot_user_ids); + td::Result>> get_inline_query_results( + const Query *query, td::JsonValue &&value, BotUserIds &bot_user_ids) const; struct BotCommandScope { object_ptr scope_; @@ -663,9 +664,10 @@ class Client final : public WebhookActor::Callback { td::string text, object_ptr link_preview_options, td::string parse_mode, td::JsonValue &&input_entities); - static td::Result> get_input_rich_message(const Query *query); + td::Result> get_input_rich_message(const Query *query) const; - static td::Result> get_input_rich_message(td::JsonValue &&value); + td::Result> get_input_rich_message(const Query *query, + td::JsonValue &&value) const; static td::Result> get_location(const Query *query); -- cgit v1.2.3 From 868f71c068b24946ee2b8d139d437666eb7cab9c Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 3 Jul 2026 21:50:41 +0300 Subject: Add Client::get_rich_text. --- telegram-bot-api/Client.cpp | 138 ++++++++++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 2 + 2 files changed, 140 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index ce97bba..965c437 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -11981,6 +11981,144 @@ td::Result> Client::get_input_messa return make_object(std::move(formatted_text), std::move(link_preview_options), false); } +td::Result> Client::get_rich_text(td::JsonValue &&value) { + switch (value.type()) { + case td::JsonValue::Type::Null: + return nullptr; + case td::JsonValue::Type::String: + return make_object(value.get_string().str()); + case td::JsonValue::Type::Array: { + td::vector> texts; + for (auto &input_text : value.get_array()) { + TRY_RESULT(text, get_rich_text(std::move(input_text))); + texts.push_back(std::move(text)); + } + return make_object(std::move(texts)); + } + case td::JsonValue::Type::Object: { + auto &object = value.get_object(); + TRY_RESULT(type, object.get_required_string_field("type")); + if (type == "bold") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + return make_object(std::move(text)); + } + if (type == "italic") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + return make_object(std::move(text)); + } + if (type == "underline") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + return make_object(std::move(text)); + } + if (type == "strikethrough") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + return make_object(std::move(text)); + } + if (type == "spoiler") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + return make_object(std::move(text)); + } + if (type == "date_time") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + TRY_RESULT(unix_time, object.get_required_int_field("unix_time")); + TRY_RESULT(format, object.get_optional_string_field("date_time_format")); + TRY_RESULT(formatting_type, get_date_time_formatting_type(format)); + return make_object(std::move(text), unix_time, std::move(formatting_type)); + } + if (type == "mention") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + return make_object(std::move(text), td::string()); + } + if (type == "hashtag") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + return make_object(std::move(text), td::string()); + } + if (type == "cashtag") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + return make_object(std::move(text), td::string()); + } + if (type == "bot_command") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + return make_object(std::move(text), td::string()); + } + if (type == "code") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + return make_object(std::move(text)); + } + if (type == "text_mention") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + TRY_RESULT(user, object.extract_required_field("user", td::JsonValue::Type::Object)); + CHECK(user.type() == td::JsonValue::Type::Object); + const auto &user_object = user.get_object(); + TRY_RESULT(user_id, user_object.get_required_long_field("id")); + return make_object(std::move(text), user_id); + } + if (type == "url") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + TRY_RESULT(url, object.get_required_string_field("url")); + return make_object(std::move(text), url, false); + } + if (type == "email_address") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + TRY_RESULT(email_address, object.get_required_string_field("email_address")); + return make_object(std::move(text), email_address); + } + if (type == "bank_card_number") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + return make_object(std::move(text), td::string()); + } + if (type == "subscript") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + return make_object(std::move(text)); + } + if (type == "superscript") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + return make_object(std::move(text)); + } + if (type == "marked") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + return make_object(std::move(text)); + } + if (type == "phone_number") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + TRY_RESULT(phone_number, object.get_required_string_field("phone_number")); + return make_object(std::move(text), phone_number); + } + if (type == "custom_emoji") { + TRY_RESULT(custom_emoji_id, object.get_required_long_field("custom_emoji_id")); + TRY_RESULT(alternative_text, object.get_required_string_field("alternative_text")); + return make_object(custom_emoji_id, alternative_text); + } + if (type == "mathematical_expression") { + TRY_RESULT(expression, object.get_required_string_field("expression")); + return make_object(expression); + } + if (type == "reference") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + TRY_RESULT(name, object.get_required_string_field("name")); + return make_object(name, std::move(text)); + } + if (type == "reference_link") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + TRY_RESULT(reference_name, object.get_required_string_field("reference_name")); + return make_object(std::move(text), reference_name, td::string()); + } + if (type == "anchor") { + TRY_RESULT(name, object.get_required_string_field("name")); + return make_object(name); + } + if (type == "anchor_link") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + TRY_RESULT(anchor_name, object.get_required_string_field("anchor_name")); + return make_object(std::move(text), anchor_name, td::string()); + } + return td::Status::Error(400, "Unsupported rich text type"); + } + default: + return td::Status::Error(400, "Invalid rich text specified"); + } +} + td::Result> Client::get_input_rich_message(const Query *query) const { auto rich_message = query->arg("rich_message"); if (rich_message.empty()) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index d95a03e..c5bdf03 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -664,6 +664,8 @@ class Client final : public WebhookActor::Callback { td::string text, object_ptr link_preview_options, td::string parse_mode, td::JsonValue &&input_entities); + static td::Result> get_rich_text(td::JsonValue &&value); + td::Result> get_input_rich_message(const Query *query) const; td::Result> get_input_rich_message(const Query *query, -- cgit v1.2.3 From 643f0ffdea033914dfebbb1211294059ef905605 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 3 Jul 2026 22:18:02 +0300 Subject: Add Client::get_page_block_caption. --- telegram-bot-api/Client.cpp | 15 +++++++++++++++ telegram-bot-api/Client.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 965c437..11e22b1 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -11981,6 +11981,21 @@ td::Result> Client::get_input_messa return make_object(std::move(formatted_text), std::move(link_preview_options), false); } +td::Result> Client::get_page_block_caption(td::JsonValue &&value) { + switch (value.type()) { + case td::JsonValue::Type::Null: + return nullptr; + case td::JsonValue::Type::Object: { + auto &object = value.get_object(); + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + TRY_RESULT(credit, get_rich_text(object.extract_field("credit"))); + return make_object(std::move(text), std::move(credit)); + } + default: + return td::Status::Error(400, "RichBlockCaption must be an object"); + } +} + td::Result> Client::get_rich_text(td::JsonValue &&value) { switch (value.type()) { case td::JsonValue::Type::Null: diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index c5bdf03..7a896a3 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -664,6 +664,8 @@ class Client final : public WebhookActor::Callback { td::string text, object_ptr link_preview_options, td::string parse_mode, td::JsonValue &&input_entities); + static td::Result> get_page_block_caption(td::JsonValue &&value); + static td::Result> get_rich_text(td::JsonValue &&value); td::Result> get_input_rich_message(const Query *query) const; -- cgit v1.2.3 From fe131c7a444fc43431f3bc888c7802e38aa8fca9 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 3 Jul 2026 23:58:00 +0300 Subject: Add get_page_block_table_cell. --- telegram-bot-api/Client.cpp | 39 +++++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 2 ++ 2 files changed, 41 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 11e22b1..23a2e86 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -11996,6 +11996,45 @@ td::Result> Client::get_page_block_ } } +td::Result> Client::get_page_block_table_cell(td::JsonValue &&value) { + if (value.type() != td::JsonValue::Type::Object) { + return td::Status::Error(400, "RichBlockTableCell must be an object"); + } + + auto &object = value.get_object(); + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + TRY_RESULT(is_header, object.get_optional_bool_field("is_header")); + TRY_RESULT(colspan, object.get_optional_int_field("colspan")); + TRY_RESULT(rowspan, object.get_optional_int_field("rowspan")); + + object_ptr align; + TRY_RESULT(align_str, object.get_optional_string_field("align")); + if (align_str == "left" || (align_str.empty() && !is_header)) { + align = make_object(); + } else if (align_str == "center" || (align_str.empty() && is_header)) { + align = make_object(); + } else if (align_str == "right") { + align = make_object(); + } else { + return td::Status::Error(400, "Invalid horizontal alignment specified"); + } + + object_ptr valign; + TRY_RESULT(valign_str, object.get_optional_string_field("valign")); + if (valign_str == "top") { + valign = make_object(); + } else if (valign_str == "middle" || valign_str.empty()) { + valign = make_object(); + } else if (valign_str == "bottom") { + valign = make_object(); + } else { + return td::Status::Error(400, "Invalid vertical alignment specified"); + } + + return make_object(std::move(text), is_header, colspan, rowspan, std::move(align), + std::move(valign)); +} + td::Result> Client::get_rich_text(td::JsonValue &&value) { switch (value.type()) { case td::JsonValue::Type::Null: diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 7a896a3..d32096f 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -666,6 +666,8 @@ class Client final : public WebhookActor::Callback { static td::Result> get_page_block_caption(td::JsonValue &&value); + static td::Result> get_page_block_table_cell(td::JsonValue &&value); + static td::Result> get_rich_text(td::JsonValue &&value); td::Result> get_input_rich_message(const Query *query) const; -- cgit v1.2.3 From a2cde3781bc62da55e872e9763d423cd0036e06c Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 4 Jul 2026 00:12:45 +0300 Subject: Simplify Client::get_inline_query_results. --- telegram-bot-api/Client.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 23a2e86..613769e 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -10873,18 +10873,14 @@ td::Result>> Clien td::Result>> Client::get_inline_query_results( const Query *query, td::JsonValue &&values, BotUserIds &bot_user_ids) const { - if (values.type() == td::JsonValue::Type::Null) { - return td::vector>(); - } + td::vector> inline_query_results; if (values.type() != td::JsonValue::Type::Array) { + if (values.type() == td::JsonValue::Type::Null) { + return std::move(inline_query_results); + } return td::Status::Error(400, "Expected an Array of inline query results"); } - constexpr std::size_t MAX_INLINE_QUERY_RESULT_COUNT = 50; - if (values.get_array().size() > MAX_INLINE_QUERY_RESULT_COUNT) { - return td::Status::Error(400, "Too many inline query results specified"); - } - td::vector> inline_query_results; for (auto &value : values.get_array()) { auto r_inline_query_result = get_inline_query_result(query, std::move(value), bot_user_ids); if (r_inline_query_result.is_error()) { -- cgit v1.2.3 From 4aee5d22a81a36d46d594cf70b4a6cbd07c85b69 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 4 Jul 2026 00:37:27 +0300 Subject: Pass JsonValue by rvalue reference. --- telegram-bot-api/Client.cpp | 40 +++++++++++++++++++--------------------- telegram-bot-api/Client.h | 14 +++++++------- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 613769e..ec86c5b 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -10156,7 +10156,7 @@ td::Result> Client::get_keyboard_ return nullptr; } -td::Result> Client::get_keyboard_button(td::JsonValue &button) { +td::Result> Client::get_keyboard_button(td::JsonValue &&button) { if (button.type() == td::JsonValue::Type::Object) { auto &object = button.get_object(); @@ -10174,7 +10174,7 @@ td::Result> Client::get_keyboard_butt } td::Result> Client::get_inline_keyboard_button( - td::JsonValue &button, BotUserIds &bot_user_ids) { + td::JsonValue &&button, BotUserIds &bot_user_ids) { if (button.type() != td::JsonValue::Type::Object) { return td::Status::Error(400, "InlineKeyboardButton must be an Object"); } @@ -10329,7 +10329,7 @@ td::Result> Client::get_reply_markup(td: return td::Status::Error(400, "Field \"keyboard\" must be an Array of Arrays"); } for (auto &button : row.get_array()) { - auto r_button = get_keyboard_button(button); + auto r_button = get_keyboard_button(std::move(button)); if (r_button.is_error()) { return td::Status::Error(400, PSLICE() << "Can't parse keyboard button: " << r_button.error().message()); } @@ -10350,7 +10350,7 @@ td::Result> Client::get_reply_markup(td: "Field \"inline_keyboard\" of the InlineKeyboardMarkup must be an Array of Arrays"); } for (auto &button : inline_row.get_array()) { - auto r_button = get_inline_keyboard_button(button, bot_user_ids); + auto r_button = get_inline_keyboard_button(std::move(button), bot_user_ids); if (r_button.is_error()) { return td::Status::Error(400, PSLICE() << "Can't parse inline keyboard button: " << r_button.error().message()); @@ -10447,7 +10447,7 @@ td::Result> Client::get_input return make_object(std::move(price), send_date); } -td::Result> Client::get_labeled_price_part(td::JsonValue &value) { +td::Result> Client::get_labeled_price_part(td::JsonValue &&value) { if (value.type() != td::JsonValue::Type::Object) { return td::Status::Error(400, "LabeledPrice must be an Object"); } @@ -10464,14 +10464,14 @@ td::Result> Client::get_labeled_pri } td::Result>> Client::get_labeled_price_parts( - td::JsonValue &value) { + td::JsonValue &&value) { if (value.type() != td::JsonValue::Type::Array) { return td::Status::Error(400, "Expected an Array of labeled prices"); } td::vector> prices; for (auto &price : value.get_array()) { - auto r_labeled_price = get_labeled_price_part(price); + auto r_labeled_price = get_labeled_price_part(std::move(price)); if (r_labeled_price.is_error()) { return td::Status::Error(400, PSLICE() << "Can't parse labeled price: " << r_labeled_price.error().message()); } @@ -10484,7 +10484,7 @@ td::Result>> Client::get return std::move(prices); } -td::Result> Client::get_suggested_tip_amounts(td::JsonValue &value) { +td::Result> Client::get_suggested_tip_amounts(td::JsonValue &&value) { if (value.type() != td::JsonValue::Type::Array) { return td::Status::Error(400, "Expected an Array of suggested tip amounts"); } @@ -10508,7 +10508,7 @@ td::Result> Client::get_suggested_tip_amounts(td::JsonValu return std::move(suggested_tip_amounts); } -td::Result> Client::get_shipping_option(td::JsonValue &option) { +td::Result> Client::get_shipping_option(td::JsonValue &&option) { if (option.type() != td::JsonValue::Type::Object) { return td::Status::Error(400, "ShippingOption must be an Object"); } @@ -10527,7 +10527,7 @@ td::Result> Client::get_shipping_opti TRY_RESULT(prices_json, object.extract_required_field("prices", td::JsonValue::Type::Array)); - auto r_prices = get_labeled_price_parts(prices_json); + auto r_prices = get_labeled_price_parts(std::move(prices_json)); if (r_prices.is_error()) { return td::Status::Error(400, PSLICE() << "Can't parse shipping option prices: " << r_prices.error().message()); } @@ -10555,7 +10555,7 @@ td::Result>> Client::get_s td::vector> options; for (auto &option : value.get_array()) { - auto r_shipping_option = get_shipping_option(option); + auto r_shipping_option = get_shipping_option(std::move(option)); if (r_shipping_option.is_error()) { return td::Status::Error(400, PSLICE() << "Can't parse shipping option: " << r_shipping_option.error().message()); } @@ -10695,10 +10695,7 @@ td::Result> Client::get_input_thumbna } td::Result> Client::get_input_message_content( - const Query *query, td::JsonValue &input_message_content, bool is_input_message_content_required) const { - CHECK(input_message_content.type() == td::JsonValue::Type::Object); - auto &object = input_message_content.get_object(); - + const Query *query, td::JsonObject &object, bool is_input_message_content_required) const { if (object.has_field("rich_message")) { TRY_RESULT(rich_message, object.extract_required_field("rich_message", td::JsonValue::Type::Object)); TRY_RESULT(input_rich_message, get_input_rich_message(query, std::move(rich_message))); @@ -10762,14 +10759,14 @@ td::Result> Client::get_input_me 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)); + TRY_RESULT(prices, get_labeled_price_parts(std::move(prices_object))); TRY_RESULT(provider_data, object.get_optional_string_field("provider_data")); TRY_RESULT(max_tip_amount, object.get_optional_long_field("max_tip_amount")); td::vector suggested_tip_amounts; TRY_RESULT(suggested_tip_amounts_array, object.extract_optional_field("suggested_tip_amounts", td::JsonValue::Type::Array)); if (suggested_tip_amounts_array.type() == td::JsonValue::Type::Array) { - TRY_RESULT_ASSIGN(suggested_tip_amounts, get_suggested_tip_amounts(suggested_tip_amounts_array)); + TRY_RESULT_ASSIGN(suggested_tip_amounts, get_suggested_tip_amounts(std::move(suggested_tip_amounts_array))); } TRY_RESULT(photo_url, object.get_optional_string_field("photo_url")); TRY_RESULT(photo_size, object.get_optional_int_field("photo_size")); @@ -10943,8 +10940,9 @@ td::Result> Client::get_inlin input_message_content = std::move(input_message_text); } } else { + auto &input_message_content_object = input_message_content_obj.get_object(); TRY_RESULT(input_message_content_result, - get_input_message_content(query, input_message_content_obj, is_input_message_content_required)); + get_input_message_content(query, input_message_content_object, is_input_message_content_required)); input_message_content = std::move(input_message_content_result); } TRY_RESULT(input_caption, object.get_optional_string_field("caption")); @@ -12899,7 +12897,7 @@ td::Result> Client::get_input_me return td::Status::Error(400, "Can't parse prices JSON object"); } - TRY_RESULT(prices, get_labeled_price_parts(r_labeled_price_parts_value.ok_ref())); + TRY_RESULT(prices, get_labeled_price_parts(r_labeled_price_parts_value.move_as_ok())); int64 max_tip_amount = 0; td::vector suggested_tip_amounts; @@ -12920,7 +12918,7 @@ td::Result> Client::get_input_me return td::Status::Error(400, "Can't parse suggested_tip_amounts JSON object"); } - TRY_RESULT_ASSIGN(suggested_tip_amounts, get_suggested_tip_amounts(r_suggested_tip_amounts_value.ok_ref())); + TRY_RESULT_ASSIGN(suggested_tip_amounts, get_suggested_tip_amounts(r_suggested_tip_amounts_value.move_as_ok())); } } @@ -15299,7 +15297,7 @@ td::Status Client::process_save_prepared_keyboard_button_query(PromisedQueryPtr return td::Status::Error(400, "Can't parse keyboard button JSON object"); } auto value = r_value.move_as_ok(); - auto r_button = get_keyboard_button(value); + auto r_button = get_keyboard_button(std::move(value)); if (r_button.is_error()) { return td::Status::Error(400, PSLICE() << "Can't parse keyboard button: " << r_button.error().message()); } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index d32096f..25ecad0 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -512,12 +512,12 @@ class Client final : public WebhookActor::Callback { static td::Result> get_keyboard_button_type(td::JsonObject &object); - static td::Result> get_keyboard_button(td::JsonValue &button); + static td::Result> get_keyboard_button(td::JsonValue &&button); static td::Result> get_inline_keyboard_button_type( td::JsonObject &object, BotUserIds &bot_user_ids); - static td::Result> get_inline_keyboard_button(td::JsonValue &button, + static td::Result> get_inline_keyboard_button(td::JsonValue &&button, BotUserIds &bot_user_ids); static td::Result> get_reply_markup(const Query *query, BotUserIds &bot_user_ids); @@ -530,20 +530,20 @@ class Client final : public WebhookActor::Callback { static td::Result> get_input_suggested_post_info(td::JsonValue &&value); - static td::Result> get_labeled_price_part(td::JsonValue &value); + static td::Result> get_labeled_price_part(td::JsonValue &&value); - static td::Result>> get_labeled_price_parts(td::JsonValue &value); + static td::Result>> get_labeled_price_parts(td::JsonValue &&value); - static td::Result> get_suggested_tip_amounts(td::JsonValue &value); + static td::Result> get_suggested_tip_amounts(td::JsonValue &&value); - static td::Result> get_shipping_option(td::JsonValue &option); + static td::Result> get_shipping_option(td::JsonValue &&option); static td::Result>> get_shipping_options(const Query *query); static td::Result>> get_shipping_options(td::JsonValue &&value); td::Result> get_input_message_content( - const Query *query, td::JsonValue &input_message_content, bool is_input_message_content_required) const; + const Query *query, td::JsonObject &object, bool is_input_message_content_required) const; static object_ptr get_chat_action(const Query *query); -- cgit v1.2.3 From 58a965b2af611578c100094993a37725178749d4 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 4 Jul 2026 00:40:15 +0300 Subject: Add and use Client::get_array. --- telegram-bot-api/Client.cpp | 155 +++++++++----------------------------------- telegram-bot-api/Client.h | 10 +-- 2 files changed, 36 insertions(+), 129 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index ec86c5b..5800e09 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -9957,6 +9957,28 @@ bool Client::to_bool(td::MutableSlice value) { return value == "true" || value == "yes" || value == "1"; } +template +td::Result> Client::get_array(td::JsonValue &&values, td::Slice class_name, + td::Result (*func)(td::JsonValue &&value)) { + td::vector items; + if (values.type() != td::JsonValue::Type::Array) { + if (values.type() == td::JsonValue::Type::Null) { + return std::move(items); + } + return td::Status::Error(400, PSLICE() << "Expected an Array of " << class_name); + } + + for (auto &value : values.get_array()) { + auto r_item = func(std::move(value)); + if (r_item.is_error()) { + return td::Status::Error(400, PSLICE() << "Can't parse " << class_name << ": " << r_item.error().message()); + } + items.push_back(r_item.move_as_ok()); + } + + return std::move(items); +} + td_api::object_ptr Client::get_input_message_reply_to( CheckedReplyParameters &&reply_parameters) { if (reply_parameters.reply_to_ephemeral_message_id > 0) { @@ -10324,18 +10346,7 @@ td::Result> Client::get_reply_markup(td: TRY_RESULT(keyboard, object.extract_optional_field("keyboard", td::JsonValue::Type::Array)); if (keyboard.type() == td::JsonValue::Type::Array) { for (auto &row : keyboard.get_array()) { - td::vector> new_row; - if (row.type() != td::JsonValue::Type::Array) { - return td::Status::Error(400, "Field \"keyboard\" must be an Array of Arrays"); - } - for (auto &button : row.get_array()) { - auto r_button = get_keyboard_button(std::move(button)); - if (r_button.is_error()) { - return td::Status::Error(400, PSLICE() << "Can't parse keyboard button: " << r_button.error().message()); - } - new_row.push_back(r_button.move_as_ok()); - } - + TRY_RESULT(new_row, get_array(std::move(row), "KeyboardButton", get_keyboard_button)); rows.push_back(std::move(new_row)); } } @@ -10465,23 +10476,7 @@ td::Result> Client::get_labeled_pri td::Result>> Client::get_labeled_price_parts( td::JsonValue &&value) { - if (value.type() != td::JsonValue::Type::Array) { - return td::Status::Error(400, "Expected an Array of labeled prices"); - } - - td::vector> prices; - for (auto &price : value.get_array()) { - auto r_labeled_price = get_labeled_price_part(std::move(price)); - if (r_labeled_price.is_error()) { - return td::Status::Error(400, PSLICE() << "Can't parse labeled price: " << r_labeled_price.error().message()); - } - prices.push_back(r_labeled_price.move_as_ok()); - } - if (prices.empty()) { - return td::Status::Error(400, "There must be at least one price"); - } - - return std::move(prices); + return get_array(std::move(value), "LabeledPrice", get_labeled_price_part); } td::Result> Client::get_suggested_tip_amounts(td::JsonValue &&value) { @@ -10545,27 +10540,7 @@ td::Result>> Client::get_s return td::Status::Error(400, "Can't parse shipping options JSON object"); } - return get_shipping_options(r_value.move_as_ok()); -} - -td::Result>> Client::get_shipping_options(td::JsonValue &&value) { - if (value.type() != td::JsonValue::Type::Array) { - return td::Status::Error(400, "Expected an Array of shipping options"); - } - - td::vector> options; - for (auto &option : value.get_array()) { - auto r_shipping_option = get_shipping_option(std::move(option)); - if (r_shipping_option.is_error()) { - return td::Status::Error(400, PSLICE() << "Can't parse shipping option: " << r_shipping_option.error().message()); - } - options.push_back(r_shipping_option.move_as_ok()); - } - if (options.empty()) { - return td::Status::Error(400, "There must be at least one shipping option"); - } - - return std::move(options); + return get_array(r_value.move_as_ok(), "ShippingOption", get_shipping_option); } td_api::object_ptr Client::get_chat_action(const Query *query) { @@ -11267,20 +11242,7 @@ td::Result>> Client::get_bot_c return td::Status::Error(400, "Can't parse commands 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 BotCommand"); - } - - td::vector> bot_commands; - for (auto &command : value.get_array()) { - auto r_bot_command = get_bot_command(std::move(command)); - if (r_bot_command.is_error()) { - return td::Status::Error(400, PSLICE() << "Can't parse BotCommand: " << r_bot_command.error().message()); - } - bot_commands.push_back(r_bot_command.move_as_ok()); - } - return std::move(bot_commands); + return get_array(r_value.move_as_ok(), "BotCommand", get_bot_command); } td::Result> Client::get_bot_menu_button(td::JsonValue &&value) { @@ -11755,20 +11717,7 @@ td::Result>> Cl return td::Status::Error(400, "Can't parse errors 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 PassportElementError"); - } - - td::vector> errors; - for (auto &input_error : value.get_array()) { - auto r_error = get_passport_element_error(std::move(input_error)); - if (r_error.is_error()) { - return td::Status::Error(400, PSLICE() << "Can't parse PassportElementError: " << r_error.error().message()); - } - errors.push_back(r_error.move_as_ok()); - } - return std::move(errors); + return get_array(r_value.move_as_ok(), "PassportElementError", get_passport_element_error); } td::JsonValue Client::get_input_entities(const Query *query, td::Slice field_name) { @@ -12459,7 +12408,7 @@ td::Result> Client::get_input_voice_n } td::Result> Client::get_input_checklist_task( - td::JsonValue &&input_task) const { + td::JsonValue &&input_task) { if (input_task.type() != td::JsonValue::Type::Object) { return td::Status::Error("expected an Object"); } @@ -12474,23 +12423,6 @@ td::Result> Client::get_input_che return make_object(id, std::move(text)); } -td::Result>> Client::get_input_checklist_tasks( - td::JsonValue &&value) const { - if (value.type() != td::JsonValue::Type::Array) { - return td::Status::Error(400, "Expected an Array of InputChecklistTask"); - } - - td::vector> tasks; - for (auto &input_task : value.get_array()) { - auto r_task = get_input_checklist_task(std::move(input_task)); - if (r_task.is_error()) { - return td::Status::Error(400, PSLICE() << "Can't parse InputChecklistTask: " << r_task.error().message()); - } - tasks.push_back(r_task.move_as_ok()); - } - return std::move(tasks); -} - td::Result> Client::get_input_checklist( const Query *query, td::JsonValue &&input_checklist) const { if (input_checklist.type() != td::JsonValue::Type::Object) { @@ -12505,7 +12437,7 @@ td::Result> Client::get_input_checkli TRY_RESULT(others_can_add_tasks, object.get_optional_bool_field("others_can_add_tasks")); TRY_RESULT(others_can_mark_tasks_as_done, object.get_optional_bool_field("others_can_mark_tasks_as_done")); TRY_RESULT(input_tasks, object.extract_required_field("tasks", td::JsonValue::Type::Array)); - TRY_RESULT(tasks, get_input_checklist_tasks(std::move(input_tasks))); + TRY_RESULT(tasks, get_array(std::move(input_tasks), "InputChecklistTask", get_input_checklist_task)); return make_object(std::move(title), std::move(tasks), others_can_add_tasks, others_can_mark_tasks_as_done); @@ -13027,20 +12959,7 @@ td::Result>> Client::get_rea 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); + return get_array(r_value.move_as_ok(), "ReactionType", get_reaction_type); } td::Result> Client::get_input_story_area_type(td::JsonValue &&value) { @@ -13129,19 +13048,7 @@ td::Result> Client::get_input_story_ return td::Status::Error(400, "Can't parse story areas 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 InputStoryArea"); - } - - td::vector> input_story_areas; - for (auto &area : value.get_array()) { - auto r_input_story_area = get_input_story_area(std::move(area)); - if (r_input_story_area.is_error()) { - return td::Status::Error(400, PSLICE() << "Can't parse InputStoryArea: " << r_input_story_area.error().message()); - } - input_story_areas.push_back(r_input_story_area.move_as_ok()); - } + TRY_RESULT(input_story_areas, get_array(r_value.move_as_ok(), "InputStoryArea", get_input_story_area)); return make_object(std::move(input_story_areas)); } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 25ecad0..dc3001d 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -499,6 +499,10 @@ class Client final : public WebhookActor::Callback { static bool is_reply_in_same_topic(const object_ptr &reply_topic_id, const object_ptr &topic_id); + template + static td::Result> get_array(td::JsonValue &&values, td::Slice class_name, + td::Result (*func)(td::JsonValue &&value)); + static object_ptr get_input_message_reply_to(CheckedReplyParameters &&reply_parameters); static object_ptr get_input_message_reply_to_unchecked( @@ -540,8 +544,6 @@ class Client final : public WebhookActor::Callback { static td::Result>> get_shipping_options(const Query *query); - static td::Result>> get_shipping_options(td::JsonValue &&value); - td::Result> get_input_message_content( const Query *query, td::JsonObject &object, bool is_input_message_content_required) const; @@ -703,9 +705,7 @@ class Client final : public WebhookActor::Callback { static td::Result> get_input_voice_note( const td::JsonObject &object, object_ptr &&input_file); - td::Result> get_input_checklist_task(td::JsonValue &&input_task) const; - - td::Result>> get_input_checklist_tasks(td::JsonValue &&value) const; + static td::Result> get_input_checklist_task(td::JsonValue &&input_task); td::Result> get_input_checklist(const Query *query, td::JsonValue &&input_checklist) const; -- cgit v1.2.3 From 58a11c65eef93451da3bd59f8121798b1b3c3458 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 5 Jul 2026 00:08:07 +0300 Subject: Use get_array in get_suggested_tip_amounts. --- telegram-bot-api/Client.cpp | 43 +++++++++++++++++-------------------------- telegram-bot-api/Client.h | 4 +++- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 5800e09..24b81af 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -10479,28 +10479,24 @@ td::Result>> Client::get return get_array(std::move(value), "LabeledPrice", get_labeled_price_part); } -td::Result> Client::get_suggested_tip_amounts(td::JsonValue &&value) { - if (value.type() != td::JsonValue::Type::Array) { - return td::Status::Error(400, "Expected an Array of suggested tip amounts"); +td::Result Client::get_suggested_tip_amount(td::JsonValue &&value) { + td::Slice number; + if (value.type() == td::JsonValue::Type::Number) { + number = value.get_number(); + } else if (value.type() == td::JsonValue::Type::String) { + number = value.get_string(); + } else { + return td::Status::Error(400, "Suggested tip amount must be of type Number or String"); } - - td::vector suggested_tip_amounts; - for (auto &amount : value.get_array()) { - td::Slice number; - if (amount.type() == td::JsonValue::Type::Number) { - number = amount.get_number(); - } else if (amount.type() == td::JsonValue::Type::String) { - number = amount.get_string(); - } else { - return td::Status::Error(400, "Suggested tip amount must be of type Number or String"); - } - auto parsed_amount = td::to_integer_safe(number); - if (parsed_amount.is_error()) { - return td::Status::Error(400, "Can't parse suggested tip amount as Number"); - } - suggested_tip_amounts.push_back(parsed_amount.ok()); + auto parsed_amount = td::to_integer_safe(number); + if (parsed_amount.is_error()) { + return td::Status::Error(400, "Can't parse suggested tip amount as Number"); } - return std::move(suggested_tip_amounts); + return parsed_amount.ok(); +} + +td::Result> Client::get_suggested_tip_amounts(td::JsonValue &&value) { + return get_array(std::move(value), "suggested tip amount", get_suggested_tip_amount); } td::Result> Client::get_shipping_option(td::JsonValue &&option) { @@ -10737,12 +10733,7 @@ td::Result> Client::get_input_me TRY_RESULT(prices, get_labeled_price_parts(std::move(prices_object))); TRY_RESULT(provider_data, object.get_optional_string_field("provider_data")); TRY_RESULT(max_tip_amount, object.get_optional_long_field("max_tip_amount")); - td::vector suggested_tip_amounts; - TRY_RESULT(suggested_tip_amounts_array, - object.extract_optional_field("suggested_tip_amounts", td::JsonValue::Type::Array)); - if (suggested_tip_amounts_array.type() == td::JsonValue::Type::Array) { - TRY_RESULT_ASSIGN(suggested_tip_amounts, get_suggested_tip_amounts(std::move(suggested_tip_amounts_array))); - } + TRY_RESULT(suggested_tip_amounts, get_suggested_tip_amounts(object.extract_field("suggested_tip_amounts"))); TRY_RESULT(photo_url, object.get_optional_string_field("photo_url")); TRY_RESULT(photo_size, object.get_optional_int_field("photo_size")); TRY_RESULT(photo_width, object.get_optional_int_field("photo_width")); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index dc3001d..95af8ee 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -538,6 +538,8 @@ class Client final : public WebhookActor::Callback { static td::Result>> get_labeled_price_parts(td::JsonValue &&value); + static td::Result get_suggested_tip_amount(td::JsonValue &&value); + static td::Result> get_suggested_tip_amounts(td::JsonValue &&value); static td::Result> get_shipping_option(td::JsonValue &&option); @@ -1019,7 +1021,7 @@ class Client final : public WebhookActor::Callback { void on_webhook_closed(td::Status status); - void delete_last_send_message_time(td::int64 file_size, double max_delay); + void delete_last_send_message_time(int64 file_size, double max_delay); void do_send_message(object_ptr input_message_content, PromisedQueryPtr query, bool force = false); -- cgit v1.2.3 From 97ae3cf99458cc64905f5e242fd4905587e7f7fc Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 5 Jul 2026 15:39:49 +0300 Subject: Add and use Client::get_array_generic. --- telegram-bot-api/Client.cpp | 205 ++++++++++++++------------------------------ telegram-bot-api/Client.h | 15 ++-- 2 files changed, 72 insertions(+), 148 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 24b81af..a1823ef 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -9979,6 +9979,29 @@ td::Result> Client::get_array(td::JsonValue &&values, td::Slice cl return std::move(items); } +template +td::Result>> Client::get_array_generic( + td::JsonValue &&values, td::Slice class_name, + const std::function>(td::JsonValue &&value)> &func) { + td::vector> items; + if (values.type() != td::JsonValue::Type::Array) { + if (values.type() == td::JsonValue::Type::Null) { + return std::move(items); + } + return td::Status::Error(400, PSLICE() << "Expected an Array of " << class_name); + } + + for (auto &value : values.get_array()) { + auto r_item = func(std::move(value)); + if (r_item.is_error()) { + return td::Status::Error(400, PSLICE() << "Can't parse " << class_name << ": " << r_item.error().message()); + } + items.push_back(r_item.move_as_ok()); + } + + return std::move(items); +} + td_api::object_ptr Client::get_input_message_reply_to( CheckedReplyParameters &&reply_parameters) { if (reply_parameters.reply_to_ephemeral_message_id > 0) { @@ -10354,22 +10377,12 @@ td::Result> Client::get_reply_markup(td: td::vector>> inline_rows; TRY_RESULT(inline_keyboard, object.extract_optional_field("inline_keyboard", td::JsonValue::Type::Array)); if (inline_keyboard.type() == td::JsonValue::Type::Array) { - for (auto &inline_row : inline_keyboard.get_array()) { - td::vector> new_inline_row; - if (inline_row.type() != td::JsonValue::Type::Array) { - return td::Status::Error(400, - "Field \"inline_keyboard\" of the InlineKeyboardMarkup must be an Array of Arrays"); - } - for (auto &button : inline_row.get_array()) { - auto r_button = get_inline_keyboard_button(std::move(button), bot_user_ids); - if (r_button.is_error()) { - return td::Status::Error(400, PSLICE() - << "Can't parse inline keyboard button: " << r_button.error().message()); - } - new_inline_row.push_back(r_button.move_as_ok()); - } - - inline_rows.push_back(std::move(new_inline_row)); + for (auto &row : inline_keyboard.get_array()) { + TRY_RESULT(new_row, get_array_generic( + std::move(row), "InlineKeyboardButton", [&](td::JsonValue &&button) { + return get_inline_keyboard_button(std::move(button), bot_user_ids); + })); + inline_rows.push_back(std::move(new_row)); } } @@ -10831,29 +10844,9 @@ td::Result>> Clien 400, PSLICE() << "Can't parse JSON encoded inline query results: " << r_values.error().message()); } - return get_inline_query_results(query, r_values.move_as_ok(), bot_user_ids); -} - -td::Result>> Client::get_inline_query_results( - const Query *query, td::JsonValue &&values, BotUserIds &bot_user_ids) const { - td::vector> inline_query_results; - if (values.type() != td::JsonValue::Type::Array) { - if (values.type() == td::JsonValue::Type::Null) { - return std::move(inline_query_results); - } - return td::Status::Error(400, "Expected an Array of inline query results"); - } - - for (auto &value : values.get_array()) { - auto r_inline_query_result = get_inline_query_result(query, std::move(value), bot_user_ids); - if (r_inline_query_result.is_error()) { - return td::Status::Error( - 400, PSLICE() << "Can't parse inline query result: " << r_inline_query_result.error().message()); - } - inline_query_results.push_back(r_inline_query_result.move_as_ok()); - } - - return std::move(inline_query_results); + return get_array_generic( + r_values.move_as_ok(), "InlineQueryResult", + [&](td::JsonValue &&value) { return get_inline_query_result(query, std::move(value), bot_user_ids); }); } td::Result> Client::get_inline_query_result( @@ -11574,26 +11567,10 @@ td::Result>> Client::get_new_s LOG(INFO) << "Can't parse JSON object: " << r_value.error(); return td::Status::Error(400, "Can't parse stickers 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 InputSticker"); - } - - constexpr std::size_t MAX_STICKER_COUNT = 50; - if (value.get_array().size() > MAX_STICKER_COUNT) { - return td::Status::Error(400, "Too many stickers specified"); - } - td::vector> new_stickers; - for (auto &new_sticker : value.get_array()) { - auto r_new_sticker = get_new_sticker(query, std::move(new_sticker), sticker_format_str); - if (r_new_sticker.is_error()) { - return td::Status::Error(400, PSLICE() << "Can't parse InputSticker: " << r_new_sticker.error().message()); - } - new_stickers.push_back(r_new_sticker.move_as_ok()); - } - return std::move(new_stickers); + return get_array_generic(r_value.move_as_ok(), "InputSticker", [&](td::JsonValue &&value) { + return get_new_sticker(query, std::move(value), sticker_format_str); + }); } TRY_RESULT(new_sticker, get_legacy_new_sticker(query)); @@ -12653,23 +12630,9 @@ td::Result> Client::get_input_ td::Result>> Client::get_input_rich_message_medias( const Query *query, td::JsonValue &&value) const { - td::vector> media; - if (value.type() != td::JsonValue::Type::Array) { - if (value.type() == td::JsonValue::Type::Null) { - return std::move(media); - } - return td::Status::Error(400, "Expected an Array of InputRichMessageMedia"); - } - - for (auto &input_media : value.get_array()) { - auto r_input_media = get_input_rich_message_media(query, std::move(input_media)); - if (r_input_media.is_error()) { - return td::Status::Error(400, PSLICE() - << "Can't parse InputRichMessageMedia: " << r_input_media.error().message()); - } - media.push_back(r_input_media.move_as_ok()); - } - return std::move(media); + return get_array_generic( + std::move(value), "InputRichMessageMedia", + [&](td::JsonValue &&input_media) { return get_input_rich_message_media(query, std::move(input_media)); }); } td::Result>> Client::get_input_message_contents( @@ -12683,25 +12646,9 @@ td::Result>> Client:: return td::Status::Error(400, "Can't parse media JSON object"); } - return get_input_message_contents(query, r_value.move_as_ok()); -} - -td::Result>> Client::get_input_message_contents( - const Query *query, td::JsonValue &&value) const { - if (value.type() != td::JsonValue::Type::Array) { - return td::Status::Error(400, "Expected an Array of InputMedia"); - } - - td::vector> contents; - for (auto &input_media : value.get_array()) { - auto r_input_message_content = get_input_media(query, std::move(input_media), true); - if (r_input_message_content.is_error()) { - return td::Status::Error(400, PSLICE() - << "Can't parse InputMedia: " << r_input_message_content.error().message()); - } - contents.push_back(r_input_message_content.move_as_ok()); - } - return std::move(contents); + return get_array_generic(r_value.move_as_ok(), "InputMedia", [&](td::JsonValue &&value) { + return get_input_media(query, std::move(value), true); + }); } td::Result> Client::get_input_paid_media(const Query *query, @@ -12781,24 +12728,9 @@ td::Result>> Client::get_p 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); + return get_array_generic( + r_value.move_as_ok(), "InputPaidMedia", + [&](td::JsonValue &&input_media) { return get_input_paid_media(query, std::move(input_media)); }); } td::Result> Client::get_input_message_invoice( @@ -12889,34 +12821,29 @@ td::Result>> Client::get_ return td::Status::Error(400, "Can't parse options 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 String as options"); - } - - 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"))); - auto r_media = get_input_poll_media(query, object.extract_field("media"), true); - if (r_media.is_error()) { - return td::Status::Error(400, PSLICE() << "Failed to parse poll option media: " << r_media.error().message()); - } - options.push_back(make_object(std::move(option_text), r_media.move_as_ok())); - continue; - } + return get_array_generic( + r_value.move_as_ok(), "InputPollOption", + [&](td::JsonValue &&input_option) -> td::Result> { + 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"))); + auto r_media = get_input_poll_media(query, object.extract_field("media"), true); + if (r_media.is_error()) { + return td::Status::Error(400, PSLICE() + << "Failed to parse poll option media: " << r_media.error().message()); + } + return make_object(std::move(option_text), r_media.move_as_ok()); + } - return td::Status::Error(400, "Expected an option to be of type String"); - } - options.push_back(make_object( - make_object(input_option.get_string().str(), td::Auto()), nullptr)); - } - return std::move(options); + return td::Status::Error(400, "Expected InputPollOption to be an Object"); + } + return make_object( + make_object(input_option.get_string().str(), td::Auto()), nullptr); + }); } td::Result> Client::get_reaction_type(td::JsonValue &&value) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 95af8ee..c8b7aa1 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -29,6 +29,7 @@ #include "td/utils/Status.h" #include "td/utils/WaitFreeHashMap.h" +#include #include #include #include @@ -503,6 +504,11 @@ class Client final : public WebhookActor::Callback { static td::Result> get_array(td::JsonValue &&values, td::Slice class_name, td::Result (*func)(td::JsonValue &&value)); + template + static td::Result>> get_array_generic( + td::JsonValue &&values, td::Slice class_name, + const std::function>(td::JsonValue &&value)> &func); + static object_ptr get_input_message_reply_to(CheckedReplyParameters &&reply_parameters); static object_ptr get_input_message_reply_to_unchecked( @@ -579,9 +585,6 @@ class Client final : public WebhookActor::Callback { td::Result>> get_inline_query_results( const Query *query, BotUserIds &bot_user_ids) const; - td::Result>> get_inline_query_results( - const Query *query, td::JsonValue &&value, BotUserIds &bot_user_ids) const; - struct BotCommandScope { object_ptr scope_; td::string chat_id_; @@ -739,9 +742,6 @@ class Client final : public WebhookActor::Callback { td::Result>> get_input_message_contents( const Query *query, td::Slice field_name) const; - td::Result>> 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; @@ -750,9 +750,6 @@ class Client final : public WebhookActor::Callback { 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( -- cgit v1.2.3 From d1b0d86fa02ab56beae47bfab149c02a1f16662e Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 5 Jul 2026 23:11:19 +0300 Subject: Add get_input_page_blocks. --- telegram-bot-api/Client.cpp | 161 ++++++++++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 8 +++ 2 files changed, 169 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index a1823ef..c82bb87 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -12084,6 +12084,167 @@ td::Result> Client::get_rich_text(td::JsonV } } +td::Result> Client::get_input_page_block_list_item( + const Query *query, td::JsonValue &&value) const { + if (value.type() != td::JsonValue::Type::Object) { + return td::Status::Error(400, "Object expected as InputRichBlockListItem"); + } + auto &object = value.get_object(); + TRY_RESULT(blocks, get_input_page_blocks(query, object.extract_field("blocks"))); + TRY_RESULT(has_checkbox, object.get_optional_bool_field("has_checkbox")); + TRY_RESULT(is_checked, object.get_optional_bool_field("is_checked")); + TRY_RESULT(item_value, object.get_optional_int_field("value")); + TRY_RESULT(type, object.get_optional_string_field("type")); + return make_object(std::move(blocks), has_checkbox, is_checked, item_value, type); +} + +td::Result> Client::get_input_page_block(const Query *query, + td::JsonValue &&value) const { + if (value.type() != td::JsonValue::Type::Object) { + return td::Status::Error(400, "Object expected as InputRichMessageBlock"); + } + auto &object = value.get_object(); + TRY_RESULT(type, object.get_required_string_field("type")); + if (type == "heading") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + TRY_RESULT(size, object.get_required_int_field("size")); + return make_object(std::move(text), size); + } + if (type == "paragraph") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + return make_object(std::move(text)); + } + if (type == "pre") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + TRY_RESULT(language, object.get_optional_string_field("language")); + return make_object(std::move(text), language); + } + if (type == "footer") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + return make_object(std::move(text)); + } + if (type == "thinking") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + return make_object(std::move(text)); + } + if (type == "divider") { + return make_object(); + } + if (type == "mathematical_expression") { + TRY_RESULT(expression, object.get_required_string_field("expression")); + return make_object(expression); + } + if (type == "anchor") { + TRY_RESULT(name, object.get_required_string_field("name")); + return make_object(name); + } + if (type == "list") { + TRY_RESULT(items, get_array_generic( + object.extract_field("items"), "InputRichBlockListItem", [&](td::JsonValue &&item) { + return get_input_page_block_list_item(query, std::move(item)); + })); + return make_object(std::move(items)); + } + if (type == "blockquote") { + TRY_RESULT(blocks, get_input_page_blocks(query, object.extract_field("blocks"))); + TRY_RESULT(credit, get_rich_text(object.extract_field("credit"))); + return make_object(std::move(blocks), std::move(credit)); + } + if (type == "pullquote") { + TRY_RESULT(text, get_rich_text(object.extract_field("text"))); + TRY_RESULT(credit, get_rich_text(object.extract_field("credit"))); + return make_object(std::move(text), std::move(credit)); + } + if (type == "collage") { + TRY_RESULT(blocks, get_input_page_blocks(query, object.extract_field("blocks"))); + TRY_RESULT(caption, get_page_block_caption(object.extract_field("caption"))); + return make_object(std::move(blocks), std::move(caption)); + } + if (type == "slideshow") { + TRY_RESULT(blocks, get_input_page_blocks(query, object.extract_field("blocks"))); + TRY_RESULT(caption, get_page_block_caption(object.extract_field("caption"))); + return make_object(std::move(blocks), std::move(caption)); + } + if (type == "table") { + td::vector>> cells; + TRY_RESULT(cells_array, object.extract_required_field("cells", td::JsonValue::Type::Array)); + for (auto &row : cells_array.get_array()) { + TRY_RESULT(new_row, get_array(std::move(row), "PageBlockTableCell", get_page_block_table_cell)); + cells.push_back(std::move(new_row)); + } + TRY_RESULT(caption, get_rich_text(object.extract_field("caption"))); + TRY_RESULT(is_bordered, object.get_optional_bool_field("is_bordered")); + TRY_RESULT(is_striped, object.get_optional_bool_field("is_striped")); + return make_object(std::move(caption), std::move(cells), is_bordered, is_striped); + } + if (type == "details") { + TRY_RESULT(summary, get_rich_text(object.extract_field("summary"))); + TRY_RESULT(blocks, get_input_page_blocks(query, object.extract_field("blocks"))); + TRY_RESULT(is_open, object.get_optional_bool_field("is_open")); + return make_object(std::move(summary), std::move(blocks), is_open); + } + if (type == "map") { + TRY_RESULT(location_field, object.extract_required_field("location", td::JsonValue::Type::Object)); + auto &location_object = location_field.get_object(); + TRY_RESULT(location, get_location(location_object)); + TRY_RESULT(zoom, object.get_optional_int_field("zoom")); + TRY_RESULT(width, object.get_optional_int_field("width")); + TRY_RESULT(height, object.get_optional_int_field("height")); + TRY_RESULT(caption, get_page_block_caption(object.extract_field("caption"))); + return make_object(std::move(location), zoom, width, height, std::move(caption)); + } + if (type != "animation" && type != "audio" && type != "photo" && type != "video" && type != "voice_note") { + return td::Status::Error(400, PSLICE() << "type \"" << type << "\" is unsupported"); + } + TRY_RESULT(media_field, object.extract_required_field(type, td::JsonValue::Type::Object)); + auto &media_object = media_field.get_object(); + TRY_RESULT(media_type, media_object.get_required_string_field("type")); + if (media_type != type) { + return td::Status::Error(400, PSLICE() + << "Unexpected media type \"" << media_type << "\" for block \"" << type << "\""); + } + TRY_RESULT(input_message_content, get_input_media(query, media_object, type, nullptr, false, false, false, true)); + TRY_RESULT(caption, get_page_block_caption(object.extract_field("caption"))); + TRY_RESULT(has_spoiler, media_object.get_optional_bool_field("has_spoiler")); + if (type == "animation") { + CHECK(input_message_content->get_id() == td_api::inputMessageAnimation::ID); + return make_object( + std::move(static_cast(input_message_content.get())->animation_), + std::move(caption), has_spoiler); + } + if (type == "audio") { + CHECK(input_message_content->get_id() == td_api::inputMessageAudio::ID); + return make_object( + std::move(static_cast(input_message_content.get())->audio_), std::move(caption)); + } + if (type == "photo") { + CHECK(input_message_content->get_id() == td_api::inputMessagePhoto::ID); + return make_object( + std::move(static_cast(input_message_content.get())->photo_), std::move(caption), + has_spoiler); + } + if (type == "video") { + CHECK(input_message_content->get_id() == td_api::inputMessageVideo::ID); + return make_object( + std::move(static_cast(input_message_content.get())->video_), std::move(caption), + has_spoiler); + } + if (type == "voice_note") { + CHECK(input_message_content->get_id() == td_api::inputMessageVoiceNote::ID); + return make_object( + std::move(static_cast(input_message_content.get())->voice_note_), + std::move(caption)); + } + UNREACHABLE(); +} + +td::Result>> Client::get_input_page_blocks( + const Query *query, td::JsonValue &&value) const { + return get_array_generic(std::move(value), "InputRichBlock", [&](td::JsonValue &&block) { + return get_input_page_block(query, std::move(block)); + }); +} + td::Result> Client::get_input_rich_message(const Query *query) const { auto rich_message = query->arg("rich_message"); if (rich_message.empty()) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index c8b7aa1..6ce5973 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -677,6 +677,14 @@ class Client final : public WebhookActor::Callback { static td::Result> get_rich_text(td::JsonValue &&value); + td::Result> get_input_page_block_list_item( + const Query *query, td::JsonValue &&value) const; + + td::Result> get_input_page_block(const Query *query, td::JsonValue &&value) const; + + td::Result>> get_input_page_blocks(const Query *query, + td::JsonValue &&value) const; + td::Result> get_input_rich_message(const Query *query) const; td::Result> get_input_rich_message(const Query *query, -- cgit v1.2.3 From b7d5263d674e04d5dced6f416a58bed40180df33 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 5 Jul 2026 23:14:13 +0300 Subject: Add InputRichMessage.blocks. --- telegram-bot-api/Client.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index c82bb87..173948e 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -12270,7 +12270,10 @@ td::Result> Client::get_input_rich_ TRY_RESULT(is_rtl, object.get_optional_bool_field("is_rtl")); TRY_RESULT(skip_entity_detection, object.get_optional_bool_field("skip_entity_detection")); auto result = make_object(nullptr, is_rtl, !skip_entity_detection); - if (object.has_field("markdown")) { + if (object.has_field("blocks")) { + TRY_RESULT(blocks, get_input_page_blocks(query, object.extract_field("blocks"))); + result->source_ = make_object(std::move(blocks)); + } else if (object.has_field("markdown")) { TRY_RESULT(text, object.get_required_string_field("markdown")); TRY_RESULT(media, get_input_rich_message_medias(query, object.extract_field("media"))); result->source_ = make_object(text, std::move(media)); -- cgit v1.2.3 From 60bfc54349f9c7b420bc6947de84aabd4c7ff7fa Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 8 Jul 2026 19:53:30 +0300 Subject: Add Ubuntu 26 to build instructions generator. --- build.html | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/build.html b/build.html index 1b0fdeb..a971488 100644 --- a/build.html +++ b/build.html @@ -208,6 +208,7 @@ +

@@ -496,6 +497,8 @@ function onOptionsChanged() { return '-14'; case 'Ubuntu 24': return '-18'; + case 'Ubuntu 26': + return '-21'; default: return ''; // use default version } @@ -506,6 +509,7 @@ function onOptionsChanged() { case 'Ubuntu 20': case 'Ubuntu 22': case 'Ubuntu 24': + case 'Ubuntu 26': return getClangVersionSuffix(); default: return ''; // use default version @@ -556,6 +560,7 @@ function onOptionsChanged() { case 'Ubuntu 20': case 'Ubuntu 22': case 'Ubuntu 24': + case 'Ubuntu 26': if (linux_distro.includes('Debian') && !use_root) { commands.push('su -'); } @@ -563,10 +568,7 @@ function onOptionsChanged() { commands.push(sudo + 'apt-get upgrade'); var packages = 'make git zlib1g-dev libssl-dev gperf cmake'; if (use_clang) { - 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'; - } + packages += ' clang' + getClangVersionSuffix() + ' libc++' + getLibcplusplusVersionSuffix() + '-dev libc++abi' + getLibcplusplusVersionSuffix() + '-dev'; } else { packages += ' g++'; } -- cgit v1.2.3 From 40a79c8367eaa64385b0a9a05d4949edd181bcba Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 10 Jul 2026 22:51:02 +0300 Subject: Add community cache. --- telegram-bot-api/Client.cpp | 24 +++++++++++++++++++++++- telegram-bot-api/Client.h | 8 ++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 173948e..d7ed0d0 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -54,7 +54,7 @@ Client::Client(td::ActorShared<> parent, const td::string &bot_token, bool is_te Client::~Client() { td::Scheduler::instance()->destroy_on_scheduler(SharedData::get_file_gc_scheduler_id(), messages_, users_, groups_, - supergroups_, chats_, sticker_set_names_); + supergroups_, chats_, communities_, sticker_set_names_); } int Client::get_retry_after_time(td::Slice error_message) { @@ -9663,6 +9663,12 @@ void Client::on_update(object_ptr result) { add_supergroup(supergroup_info, std::move(update->supergroup_)); break; } + case td_api::updateCommunity::ID: { + auto update = move_object_as(result); + auto *community_info = add_community_info(update->community_->id_); + add_community(community_info, std::move(update->community_)); + break; + } case td_api::updateSupergroupFullInfo::ID: { auto update = move_object_as(result); auto supergroup_id = update->supergroup_id_; @@ -17553,6 +17559,22 @@ const Client::ChatInfo *Client::get_chat(int64 chat_id) const { return chats_.get_pointer(chat_id); } +void Client::add_community(CommunityInfo *community_info, object_ptr &&community) { + community_info->name = std::move(community->name_); +} + +Client::CommunityInfo *Client::add_community_info(int64 community_id) { + auto &community_info = communities_[community_id]; + if (community_info == nullptr) { + community_info = td::make_unique(); + } + return community_info.get(); +} + +const Client::CommunityInfo *Client::get_community_info(int64 community_id) const { + return communities_.get_pointer(community_id); +} + void Client::set_chat_available_reactions(ChatInfo *chat_info, object_ptr &&available_reactions) { CHECK(chat_info != nullptr); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 6ce5973..e0b00ad 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -1210,6 +1210,13 @@ class Client final : public WebhookActor::Callback { ChatInfo *add_chat(int64 chat_id); const ChatInfo *get_chat(int64 chat_id) const; + struct CommunityInfo { + td::string name; + }; + static void add_community(CommunityInfo *community_info, object_ptr &&community); + CommunityInfo *add_community_info(int64 community_id); + const CommunityInfo *get_community_info(int64 community_id) const; + void set_chat_available_reactions(ChatInfo *chat_info, object_ptr &&available_reactions); @@ -1562,6 +1569,7 @@ class Client final : public WebhookActor::Callback { td::WaitFreeHashMap> groups_; td::WaitFreeHashMap> supergroups_; td::WaitFreeHashMap> chats_; + td::WaitFreeHashMap> communities_; td::WaitFreeHashMap> business_connections_; td::FlatHashMap> file_download_listeners_; -- cgit v1.2.3 From 9b9bb4ceb1cd6a5159cb2329fc016b4d2cd8221f Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 10 Jul 2026 23:02:29 +0300 Subject: Add Message.community_chat_added/removed. --- telegram-bot-api/Client.cpp | 40 +++++++++++++++++++++++++++++++++++++--- telegram-bot-api/Client.h | 2 ++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index d7ed0d0..66759f7 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -461,6 +461,23 @@ class Client::JsonDatedFiles final : public td::Jsonable { const Client *client_; }; +class Client::JsonCommunity final : public td::Jsonable { + public: + JsonCommunity(int64 community_id, const Client *client) : community_id_(community_id), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + auto community_info = client_->get_community_info(community_id_); + CHECK(community_info != nullptr); + object("id", community_id_); + object("name", community_info->name); + } + + private: + int64 community_id_; + const Client *client_; +}; + class Client::JsonUser final : public td::Jsonable { public: JsonUser(int64 user_id, const Client *client, bool full_bot_info = false) @@ -3902,6 +3919,21 @@ class Client::JsonManagedBotUpdated final : public td::Jsonable { const Client *client_; }; +class Client::JsonCommunityChatAdded final : public td::Jsonable { + public: + JsonCommunityChatAdded(const td_api::messageChatAddedToCommunity *chat_added_to_community, const Client *client) + : chat_added_to_community_(chat_added_to_community), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("community", JsonCommunity(chat_added_to_community_->community_id_, client_)); + } + + private: + const td_api::messageChatAddedToCommunity *chat_added_to_community_; + const Client *client_; +}; + class Client::JsonGiveawayCreated final : public td::Jsonable { public: explicit JsonGiveawayCreated(const td_api::messageGiveawayCreated *giveaway_created) @@ -5289,9 +5321,13 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("rich_message", JsonRichMessage(content->message_.get(), client_)); break; } - case td_api::messageChatAddedToCommunity::ID: + case td_api::messageChatAddedToCommunity::ID: { + auto content = static_cast(message_->content.get()); + object("community_chat_added", JsonCommunityChatAdded(content, client_)); break; + } case td_api::messageChatRemovedFromCommunity::ID: + object("community_chat_removed", JsonEmptyObject()); break; default: UNREACHABLE(); @@ -18561,8 +18597,6 @@ bool Client::need_skip_update_message(int64 chat_id, const MessageInfo *message_ case td_api::messageUpgradedGiftPurchaseOfferRejected::ID: case td_api::messageChatHasProtectedContentToggled::ID: case td_api::messageChatHasProtectedContentDisableRequested::ID: - case td_api::messageChatAddedToCommunity::ID: - case td_api::messageChatRemovedFromCommunity::ID: return true; default: break; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index e0b00ad..7825fe3 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -90,6 +90,7 @@ class Client final : public WebhookActor::Callback { class JsonFile; class JsonDatedFile; class JsonDatedFiles; + class JsonCommunity; class JsonUser; class JsonUsers; class JsonReactionType; @@ -245,6 +246,7 @@ class Client final : public WebhookActor::Callback { class JsonChatShared; class JsonManagedBotCreated; class JsonManagedBotUpdated; + class JsonCommunityChatAdded; class JsonGiveawayCreated; class JsonGiveaway; class JsonGiveawayWinners; -- cgit v1.2.3 From a1794007166b175f221a7504e0a191e53361fbcf Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 10 Jul 2026 23:06:53 +0300 Subject: Add ChatFullInfo.community. --- telegram-bot-api/Client.cpp | 8 ++++++++ telegram-bot-api/Client.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 66759f7..444c43d 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1597,6 +1597,9 @@ class Client::JsonChat final : public td::Jsonable { if (user_info->personal_chat_id != 0) { object("personal_chat", JsonChat(user_info->personal_chat_id, client_)); } + if (user_info->community_id != 0) { + object("community", JsonCommunity(user_info->community_id, client_)); + } if (user_info->rating != nullptr) { object("rating", JsonUserRating(user_info->rating.get())); } @@ -1721,6 +1724,9 @@ class Client::JsonChat final : public td::Jsonable { if (supergroup_info->guard_bot_user_id != 0) { object("guard_bot", JsonUser(supergroup_info->guard_bot_user_id, client_)); } + if (supergroup_info->community_id != 0) { + object("community", JsonCommunity(supergroup_info->community_id, client_)); + } if (supergroup_info->location != nullptr) { object("location", JsonChatLocation(supergroup_info->location.get())); } @@ -9674,6 +9680,7 @@ void Client::on_update(object_ptr result) { 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_; + user_info->community_id = full_info->community_id_; break; } case td_api::updateBasicGroup::ID: { @@ -9724,6 +9731,7 @@ void Client::on_update(object_ptr result) { supergroup_info->linked_chat_id = full_info->linked_chat_id_; supergroup_info->direct_messages_chat_id = full_info->direct_messages_chat_id_; supergroup_info->guard_bot_user_id = full_info->guard_bot_user_id_; + supergroup_info->community_id = full_info->community_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_; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 7825fe3..593f1fd 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -1117,6 +1117,7 @@ class Client final : public WebhookActor::Callback { object_ptr first_profile_audio; int64 personal_chat_id = 0; int64 paid_message_star_count = 0; + int64 community_id = 0; bool have_access = false; bool can_join_groups = false; @@ -1167,6 +1168,7 @@ class Client final : public WebhookActor::Callback { int64 direct_messages_chat_id = 0; int64 paid_message_star_count = 0; int64 guard_bot_user_id = 0; + int64 community_id = 0; object_ptr location; object_ptr status; bool is_supergroup = false; -- cgit v1.2.3 From 226cfcb59865fb06e5824335f70c6c3f9d9e73a3 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 10 Jul 2026 23:14:59 +0300 Subject: Use uint64 for allowed update types. --- telegram-bot-api/Client.cpp | 16 ++++++++-------- telegram-bot-api/Client.h | 13 +++++++------ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 444c43d..c0d3bd5 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -6557,7 +6557,7 @@ class Client::JsonStarTransactions final : public td::Jsonable { class Client::JsonUpdateTypes final : public td::Jsonable { public: - explicit JsonUpdateTypes(td::uint32 update_types) : update_types_(update_types) { + explicit JsonUpdateTypes(td::uint64 update_types) : update_types_(update_types) { } void store(td::JsonValueScope *scope) const { auto array = scope->enter_array(); @@ -6572,7 +6572,7 @@ class Client::JsonUpdateTypes final : public td::Jsonable { } private: - td::uint32 update_types_; + td::uint64 update_types_; }; class Client::JsonWebhookInfo final : public td::Jsonable { @@ -9775,7 +9775,7 @@ void Client::on_update(object_ptr result) { } else { CHECK(update->value_->get_id() == td_api::optionValueInteger::ID); allowed_update_types_ = - static_cast(move_object_as(update->value_)->value_); + static_cast(move_object_as(update->value_)->value_); } } if (name == "unix_time" && update->value_->get_id() != td_api::optionValueEmpty::ID) { @@ -17951,7 +17951,7 @@ td::Slice Client::get_update_type_name(UpdateType update_type) { } } -td::uint32 Client::get_allowed_update_types(td::MutableSlice allowed_updates, bool is_internal) { +td::uint64 Client::get_allowed_update_types(td::MutableSlice allowed_updates, bool is_internal) { if (allowed_updates.empty()) { return 0; } @@ -17963,11 +17963,11 @@ td::uint32 Client::get_allowed_update_types(td::MutableSlice allowed_updates, bo return 0; } - td::uint32 result = 0; + td::uint64 result = 0; auto value = r_value.move_as_ok(); if (value.type() != td::JsonValue::Type::Array) { if (value.type() == td::JsonValue::Type::Number && is_internal) { - auto r_number = td::to_integer_safe(value.get_number()); + auto r_number = td::to_integer_safe(value.get_number()); if (r_number.is_ok() && r_number.ok() > 0) { return r_number.ok(); } @@ -17982,7 +17982,7 @@ td::uint32 Client::get_allowed_update_types(td::MutableSlice allowed_updates, bo to_lower_inplace(type_name); for (int32 i = 0; i < static_cast(UpdateType::Size); i++) { if (get_update_type_name(static_cast(i)) == type_name) { - result |= (1 << i); + result |= (static_cast(1) << i); } } } @@ -18001,7 +18001,7 @@ bool Client::update_allowed_update_types(const Query *query) { if (allowed_update_types == DEFAULT_ALLOWED_UPDATE_TYPES) { value = make_object(); } else { - value = make_object(allowed_update_types); + value = make_object(static_cast(allowed_update_types)); } send_request(make_object("xallowed_update_types", std::move(value)), td::make_unique()); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 593f1fd..50630f2 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -1503,7 +1503,7 @@ class Client final : public WebhookActor::Callback { static td::Slice get_update_type_name(UpdateType update_type); - static td::uint32 get_allowed_update_types(td::MutableSlice allowed_updates, bool is_internal); + static td::uint64 get_allowed_update_types(td::MutableSlice allowed_updates, bool is_internal); bool update_allowed_update_types(const Query *query); @@ -1534,10 +1534,11 @@ class Client final : public WebhookActor::Callback { bool have_message_access(int64 chat_id) const; // 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)); + static constexpr td::uint64 DEFAULT_ALLOWED_UPDATE_TYPES = + (static_cast(1) << static_cast(UpdateType::Size)) - 1 - + (static_cast(1) << static_cast(UpdateType::ChatMember)) - + (static_cast(1) << static_cast(UpdateType::MessageReaction)) - + (static_cast(1) << static_cast(UpdateType::MessageReactionCount)); object_ptr authorization_state_; bool was_authorized_ = false; @@ -1703,7 +1704,7 @@ class Client final : public WebhookActor::Callback { double next_bot_updates_warning_time_ = 0; bool was_bot_updates_warning_ = false; - td::uint32 allowed_update_types_ = DEFAULT_ALLOWED_UPDATE_TYPES; + td::uint64 allowed_update_types_ = DEFAULT_ALLOWED_UPDATE_TYPES; bool has_webhook_certificate_ = false; enum class WebhookQueryType { Cancel, Verify }; -- cgit v1.2.3 From d62fdf42f574c365cd7e45d2393d989737875ed3 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 10 Jul 2026 23:24:00 +0300 Subject: Add "subscription" update. --- telegram-bot-api/Client.cpp | 36 ++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 4 ++++ 2 files changed, 40 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index c0d3bd5..d83a5a6 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3925,6 +3925,31 @@ class Client::JsonManagedBotUpdated final : public td::Jsonable { const Client *client_; }; +class Client::JsonBotSubscriptionUpdated final : public td::Jsonable { + public: + JsonBotSubscriptionUpdated(const td_api::updateUserSubscription *update_user_subscription, const Client *client) + : update_user_subscription_(update_user_subscription), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("user", JsonUser(update_user_subscription_->user_id_, client_)); + object("invoice_payload", update_user_subscription_->payload_); + if (update_user_subscription_->is_canceled_) { + object("state", "canceled"); + } else if (update_user_subscription_->is_restored_) { + object("state", "active"); + } else if (update_user_subscription_->is_payment_failed_) { + object("state", "failed"); + } else { + UNREACHABLE(); + } + } + + private: + const td_api::updateUserSubscription *update_user_subscription_; + const Client *client_; +}; + class Client::JsonCommunityChatAdded final : public td::Jsonable { public: JsonCommunityChatAdded(const td_api::messageChatAddedToCommunity *chat_added_to_community, const Client *client) @@ -9827,6 +9852,9 @@ void Client::on_update(object_ptr result) { case td_api::updateManagedBot::ID: add_update_managed_bot(move_object_as(result)); break; + case td_api::updateUserSubscription::ID: + add_update_subscription(move_object_as(result)); + break; case td_api::updateNewCustomEvent::ID: add_new_custom_event(move_object_as(result)); break; @@ -17945,6 +17973,8 @@ td::Slice Client::get_update_type_name(UpdateType update_type) { return td::Slice("managed_bot"); case UpdateType::GuestMessage: return td::Slice("guest_message"); + case UpdateType::Subscription: + return td::Slice("subscription"); default: UNREACHABLE(); return td::Slice(); @@ -18320,6 +18350,12 @@ void Client::add_update_managed_bot(object_ptr &&query query->user_id_ + (static_cast(13) << 33)); } +void Client::add_update_subscription(object_ptr &&query) { + CHECK(query != nullptr); + add_update(UpdateType::Subscription, JsonBotSubscriptionUpdated(query.get(), this), 86400, + query->user_id_ + (static_cast(14) << 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 50630f2..5188d19 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -247,6 +247,7 @@ class Client final : public WebhookActor::Callback { class JsonManagedBotCreated; class JsonManagedBotUpdated; class JsonCommunityChatAdded; + class JsonBotSubscriptionUpdated; class JsonGiveawayCreated; class JsonGiveaway; class JsonGiveawayWinners; @@ -1451,6 +1452,8 @@ class Client final : public WebhookActor::Callback { void add_update_managed_bot(object_ptr &&query); + void add_update_subscription(object_ptr &&query); + void add_new_custom_event(object_ptr &&event); void add_new_custom_query(object_ptr &&query); @@ -1498,6 +1501,7 @@ class Client final : public WebhookActor::Callback { PurchasedPaidMedia, ManagedBot, GuestMessage, + Subscription, Size }; -- cgit v1.2.3 From dd8923cd7f198c9ede2d6cab210e85b6579d91b2 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 12 Jul 2026 00:14:02 +0300 Subject: Add editEphemeralMessageText. --- telegram-bot-api/Client.cpp | 25 +++++++++++++++++++++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 26 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index d83a5a6..82dd4ce 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -269,6 +269,7 @@ bool Client::init_methods() { methods_.emplace("editmessagecaption", &Client::process_edit_message_caption_query); methods_.emplace("editmessagechecklist", &Client::process_edit_message_checklist_query); methods_.emplace("editmessagereplymarkup", &Client::process_edit_message_reply_markup_query); + methods_.emplace("editephemeralmessagetext", &Client::process_edit_ephemeral_message_text_query); methods_.emplace("deletemessage", &Client::process_delete_message_query); methods_.emplace("deletemessages", &Client::process_delete_messages_query); methods_.emplace("deleteephemeralmessage", &Client::process_delete_ephemeral_message_query); @@ -14819,6 +14820,30 @@ td::Status Client::process_edit_message_reply_markup_query(PromisedQueryPtr &que return td::Status::OK(); } +td::Status Client::process_edit_ephemeral_message_text_query(PromisedQueryPtr &query) { + TRY_RESULT(input_message_text, get_input_message_text(query.get())); + auto chat_id = query->arg("chat_id"); + TRY_RESULT(receiver_user_id, get_user_id(query.get(), "receiver_user_id")); + auto ephemeral_message_id = get_integer_arg(query.get(), "ephemeral_message_id", 0); + 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_str = chat_id.str(), receiver_user_id, ephemeral_message_id, + input_message_text = std::move(input_message_text)](object_ptr reply_markup, + PromisedQueryPtr query) mutable { + check_chat(chat_id_str, AccessRights::Edit, std::move(query), + [this, receiver_user_id, ephemeral_message_id, input_message_text = std::move(input_message_text), + reply_markup = std::move(reply_markup)](int64 chat_id, PromisedQueryPtr query) mutable { + send_request(make_object( + chat_id, receiver_user_id, ephemeral_message_id, std::move(reply_markup), + std::move(input_message_text)), + td::make_unique(std::move(query))); + }); + }); + return td::Status::OK(); +} + td::Status Client::process_delete_message_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 5188d19..ef1d759 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -887,6 +887,7 @@ class Client final : public WebhookActor::Callback { td::Status process_edit_message_caption_query(PromisedQueryPtr &query); td::Status process_edit_message_checklist_query(PromisedQueryPtr &query); td::Status process_edit_message_reply_markup_query(PromisedQueryPtr &query); + td::Status process_edit_ephemeral_message_text_query(PromisedQueryPtr &query); td::Status process_delete_message_query(PromisedQueryPtr &query); td::Status process_delete_messages_query(PromisedQueryPtr &query); td::Status process_delete_ephemeral_message_query(PromisedQueryPtr &query); -- cgit v1.2.3 From 40f573f6967f34e2dfd28f85f7dd18293119bbab Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 12 Jul 2026 00:17:57 +0300 Subject: Add editEphemeralMessageCaption. --- telegram-bot-api/Client.cpp | 26 ++++++++++++++++++++++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 27 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 82dd4ce..c92f1e0 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -270,6 +270,7 @@ bool Client::init_methods() { methods_.emplace("editmessagechecklist", &Client::process_edit_message_checklist_query); methods_.emplace("editmessagereplymarkup", &Client::process_edit_message_reply_markup_query); methods_.emplace("editephemeralmessagetext", &Client::process_edit_ephemeral_message_text_query); + methods_.emplace("editephemeralmessagecaption", &Client::process_edit_ephemeral_message_caption_query); methods_.emplace("deletemessage", &Client::process_delete_message_query); methods_.emplace("deletemessages", &Client::process_delete_messages_query); methods_.emplace("deleteephemeralmessage", &Client::process_delete_ephemeral_message_query); @@ -14844,6 +14845,31 @@ td::Status Client::process_edit_ephemeral_message_text_query(PromisedQueryPtr &q return td::Status::OK(); } +td::Status Client::process_edit_ephemeral_message_caption_query(PromisedQueryPtr &query) { + auto chat_id = query->arg("chat_id"); + TRY_RESULT(receiver_user_id, get_user_id(query.get(), "receiver_user_id")); + auto ephemeral_message_id = get_integer_arg(query.get(), "ephemeral_message_id", 0); + TRY_RESULT(reply_markup, get_reply_markup(query.get(), bot_user_ids_)); + TRY_RESULT(caption, get_caption(query.get())); + auto input_message_text = make_object(std::move(caption), nullptr, false); + + resolve_reply_markup_bot_usernames( + std::move(reply_markup), std::move(query), + [this, chat_id_str = chat_id.str(), receiver_user_id, ephemeral_message_id, + input_message_text = std::move(input_message_text)](object_ptr reply_markup, + PromisedQueryPtr query) mutable { + check_chat(chat_id_str, AccessRights::Edit, std::move(query), + [this, receiver_user_id, ephemeral_message_id, input_message_text = std::move(input_message_text), + reply_markup = std::move(reply_markup)](int64 chat_id, PromisedQueryPtr query) mutable { + send_request(make_object( + chat_id, receiver_user_id, ephemeral_message_id, std::move(reply_markup), + std::move(input_message_text)), + td::make_unique(std::move(query))); + }); + }); + return td::Status::OK(); +} + td::Status Client::process_delete_message_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 ef1d759..68751de 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -888,6 +888,7 @@ class Client final : public WebhookActor::Callback { td::Status process_edit_message_checklist_query(PromisedQueryPtr &query); td::Status process_edit_message_reply_markup_query(PromisedQueryPtr &query); td::Status process_edit_ephemeral_message_text_query(PromisedQueryPtr &query); + td::Status process_edit_ephemeral_message_caption_query(PromisedQueryPtr &query); td::Status process_delete_message_query(PromisedQueryPtr &query); td::Status process_delete_messages_query(PromisedQueryPtr &query); td::Status process_delete_ephemeral_message_query(PromisedQueryPtr &query); -- cgit v1.2.3 From 1752a220755798d1f3e55f5d477a67ab43a3568f Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 12 Jul 2026 00:22:57 +0300 Subject: Add editEphemeralMessageReplyMarkup. --- telegram-bot-api/Client.cpp | 23 +++++++++++++++++++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 24 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index c92f1e0..833278a 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -271,6 +271,7 @@ bool Client::init_methods() { methods_.emplace("editmessagereplymarkup", &Client::process_edit_message_reply_markup_query); methods_.emplace("editephemeralmessagetext", &Client::process_edit_ephemeral_message_text_query); methods_.emplace("editephemeralmessagecaption", &Client::process_edit_ephemeral_message_caption_query); + methods_.emplace("editephemeralmessagereplymarkup", &Client::process_edit_ephemeral_message_reply_markup_query); methods_.emplace("deletemessage", &Client::process_delete_message_query); methods_.emplace("deletemessages", &Client::process_delete_messages_query); methods_.emplace("deleteephemeralmessage", &Client::process_delete_ephemeral_message_query); @@ -14870,6 +14871,28 @@ td::Status Client::process_edit_ephemeral_message_caption_query(PromisedQueryPtr return td::Status::OK(); } +td::Status Client::process_edit_ephemeral_message_reply_markup_query(PromisedQueryPtr &query) { + auto chat_id = query->arg("chat_id"); + TRY_RESULT(receiver_user_id, get_user_id(query.get(), "receiver_user_id")); + auto ephemeral_message_id = get_integer_arg(query.get(), "ephemeral_message_id", 0); + 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_str = chat_id.str(), receiver_user_id, ephemeral_message_id]( + object_ptr reply_markup, PromisedQueryPtr query) mutable { + check_chat(chat_id_str, AccessRights::Edit, std::move(query), + [this, receiver_user_id, ephemeral_message_id, reply_markup = std::move(reply_markup)]( + int64 chat_id, PromisedQueryPtr query) mutable { + send_request( + make_object(chat_id, receiver_user_id, ephemeral_message_id, + std::move(reply_markup), nullptr), + td::make_unique(std::move(query))); + }); + }); + return td::Status::OK(); +} + td::Status Client::process_delete_message_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 68751de..0b40bb9 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -889,6 +889,7 @@ class Client final : public WebhookActor::Callback { td::Status process_edit_message_reply_markup_query(PromisedQueryPtr &query); td::Status process_edit_ephemeral_message_text_query(PromisedQueryPtr &query); td::Status process_edit_ephemeral_message_caption_query(PromisedQueryPtr &query); + td::Status process_edit_ephemeral_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_delete_ephemeral_message_query(PromisedQueryPtr &query); -- cgit v1.2.3 From b28feeaf6b5bd2c0144153faaa7446f9c28c4736 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 12 Jul 2026 23:29:16 +0300 Subject: Add editEphemeralMessageMedia. --- telegram-bot-api/Client.cpp | 24 ++++++++++++++++++++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 25 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 833278a..484e72d 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -270,6 +270,7 @@ bool Client::init_methods() { methods_.emplace("editmessagechecklist", &Client::process_edit_message_checklist_query); methods_.emplace("editmessagereplymarkup", &Client::process_edit_message_reply_markup_query); methods_.emplace("editephemeralmessagetext", &Client::process_edit_ephemeral_message_text_query); + methods_.emplace("editephemeralmessagemedia", &Client::process_edit_ephemeral_message_media_query); methods_.emplace("editephemeralmessagecaption", &Client::process_edit_ephemeral_message_caption_query); methods_.emplace("editephemeralmessagereplymarkup", &Client::process_edit_ephemeral_message_reply_markup_query); methods_.emplace("deletemessage", &Client::process_delete_message_query); @@ -14846,6 +14847,29 @@ td::Status Client::process_edit_ephemeral_message_text_query(PromisedQueryPtr &q return td::Status::OK(); } +td::Status Client::process_edit_ephemeral_message_media_query(PromisedQueryPtr &query) { + auto chat_id = query->arg("chat_id"); + TRY_RESULT(receiver_user_id, get_user_id(query.get(), "receiver_user_id")); + auto ephemeral_message_id = get_integer_arg(query.get(), "ephemeral_message_id", 0); + TRY_RESULT(reply_markup, get_reply_markup(query.get(), bot_user_ids_)); + TRY_RESULT(input_media, get_input_media(query.get(), "media")); + + resolve_reply_markup_bot_usernames( + std::move(reply_markup), std::move(query), + [this, chat_id_str = chat_id.str(), receiver_user_id, ephemeral_message_id, input_media = std::move(input_media)]( + object_ptr reply_markup, PromisedQueryPtr query) mutable { + check_chat(chat_id_str, AccessRights::Edit, std::move(query), + [this, receiver_user_id, ephemeral_message_id, input_media = std::move(input_media), + reply_markup = std::move(reply_markup)](int64 chat_id, PromisedQueryPtr query) mutable { + send_request(make_object( + chat_id, receiver_user_id, ephemeral_message_id, std::move(reply_markup), + std::move(input_media)), + td::make_unique(std::move(query))); + }); + }); + return td::Status::OK(); +} + td::Status Client::process_edit_ephemeral_message_caption_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); TRY_RESULT(receiver_user_id, get_user_id(query.get(), "receiver_user_id")); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 0b40bb9..3fec71c 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -888,6 +888,7 @@ class Client final : public WebhookActor::Callback { td::Status process_edit_message_checklist_query(PromisedQueryPtr &query); td::Status process_edit_message_reply_markup_query(PromisedQueryPtr &query); td::Status process_edit_ephemeral_message_text_query(PromisedQueryPtr &query); + td::Status process_edit_ephemeral_message_media_query(PromisedQueryPtr &query); td::Status process_edit_ephemeral_message_caption_query(PromisedQueryPtr &query); td::Status process_edit_ephemeral_message_reply_markup_query(PromisedQueryPtr &query); td::Status process_delete_message_query(PromisedQueryPtr &query); -- cgit v1.2.3 From 52099b13dde6022dfecd05d42dba44fe34859052 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 12 Jul 2026 23:35:55 +0300 Subject: Add and use do_edit_ephemeral_message. --- telegram-bot-api/Client.cpp | 108 ++++++++++++-------------------------------- telegram-bot-api/Client.h | 3 ++ 2 files changed, 32 insertions(+), 79 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 484e72d..0d16d48 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -14825,96 +14825,21 @@ td::Status Client::process_edit_message_reply_markup_query(PromisedQueryPtr &que td::Status Client::process_edit_ephemeral_message_text_query(PromisedQueryPtr &query) { TRY_RESULT(input_message_text, get_input_message_text(query.get())); - auto chat_id = query->arg("chat_id"); - TRY_RESULT(receiver_user_id, get_user_id(query.get(), "receiver_user_id")); - auto ephemeral_message_id = get_integer_arg(query.get(), "ephemeral_message_id", 0); - 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_str = chat_id.str(), receiver_user_id, ephemeral_message_id, - input_message_text = std::move(input_message_text)](object_ptr reply_markup, - PromisedQueryPtr query) mutable { - check_chat(chat_id_str, AccessRights::Edit, std::move(query), - [this, receiver_user_id, ephemeral_message_id, input_message_text = std::move(input_message_text), - reply_markup = std::move(reply_markup)](int64 chat_id, PromisedQueryPtr query) mutable { - send_request(make_object( - chat_id, receiver_user_id, ephemeral_message_id, std::move(reply_markup), - std::move(input_message_text)), - td::make_unique(std::move(query))); - }); - }); - return td::Status::OK(); + return do_edit_ephemeral_message(std::move(input_message_text), query); } td::Status Client::process_edit_ephemeral_message_media_query(PromisedQueryPtr &query) { - auto chat_id = query->arg("chat_id"); - TRY_RESULT(receiver_user_id, get_user_id(query.get(), "receiver_user_id")); - auto ephemeral_message_id = get_integer_arg(query.get(), "ephemeral_message_id", 0); - TRY_RESULT(reply_markup, get_reply_markup(query.get(), bot_user_ids_)); TRY_RESULT(input_media, get_input_media(query.get(), "media")); - - resolve_reply_markup_bot_usernames( - std::move(reply_markup), std::move(query), - [this, chat_id_str = chat_id.str(), receiver_user_id, ephemeral_message_id, input_media = std::move(input_media)]( - object_ptr reply_markup, PromisedQueryPtr query) mutable { - check_chat(chat_id_str, AccessRights::Edit, std::move(query), - [this, receiver_user_id, ephemeral_message_id, input_media = std::move(input_media), - reply_markup = std::move(reply_markup)](int64 chat_id, PromisedQueryPtr query) mutable { - send_request(make_object( - chat_id, receiver_user_id, ephemeral_message_id, std::move(reply_markup), - std::move(input_media)), - td::make_unique(std::move(query))); - }); - }); - return td::Status::OK(); + return do_edit_ephemeral_message(std::move(input_media), query); } td::Status Client::process_edit_ephemeral_message_caption_query(PromisedQueryPtr &query) { - auto chat_id = query->arg("chat_id"); - TRY_RESULT(receiver_user_id, get_user_id(query.get(), "receiver_user_id")); - auto ephemeral_message_id = get_integer_arg(query.get(), "ephemeral_message_id", 0); - TRY_RESULT(reply_markup, get_reply_markup(query.get(), bot_user_ids_)); TRY_RESULT(caption, get_caption(query.get())); - auto input_message_text = make_object(std::move(caption), nullptr, false); - - resolve_reply_markup_bot_usernames( - std::move(reply_markup), std::move(query), - [this, chat_id_str = chat_id.str(), receiver_user_id, ephemeral_message_id, - input_message_text = std::move(input_message_text)](object_ptr reply_markup, - PromisedQueryPtr query) mutable { - check_chat(chat_id_str, AccessRights::Edit, std::move(query), - [this, receiver_user_id, ephemeral_message_id, input_message_text = std::move(input_message_text), - reply_markup = std::move(reply_markup)](int64 chat_id, PromisedQueryPtr query) mutable { - send_request(make_object( - chat_id, receiver_user_id, ephemeral_message_id, std::move(reply_markup), - std::move(input_message_text)), - td::make_unique(std::move(query))); - }); - }); - return td::Status::OK(); + return do_edit_ephemeral_message(make_object(std::move(caption), nullptr, false), query); } td::Status Client::process_edit_ephemeral_message_reply_markup_query(PromisedQueryPtr &query) { - auto chat_id = query->arg("chat_id"); - TRY_RESULT(receiver_user_id, get_user_id(query.get(), "receiver_user_id")); - auto ephemeral_message_id = get_integer_arg(query.get(), "ephemeral_message_id", 0); - 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_str = chat_id.str(), receiver_user_id, ephemeral_message_id]( - object_ptr reply_markup, PromisedQueryPtr query) mutable { - check_chat(chat_id_str, AccessRights::Edit, std::move(query), - [this, receiver_user_id, ephemeral_message_id, reply_markup = std::move(reply_markup)]( - int64 chat_id, PromisedQueryPtr query) mutable { - send_request( - make_object(chat_id, receiver_user_id, ephemeral_message_id, - std::move(reply_markup), nullptr), - td::make_unique(std::move(query))); - }); - }); - return td::Status::OK(); + return do_edit_ephemeral_message(nullptr, query); } td::Status Client::process_delete_message_query(PromisedQueryPtr &query) { @@ -17396,6 +17321,31 @@ void Client::on_sent_story(object_ptr &&story, PromisedQueryPtr q CHECK(emplace_result.second); } +td::Status Client::do_edit_ephemeral_message(object_ptr input_message_content, + PromisedQueryPtr &query) { + auto chat_id = query->arg("chat_id"); + TRY_RESULT(receiver_user_id, get_user_id(query.get(), "receiver_user_id")); + auto ephemeral_message_id = get_integer_arg(query.get(), "ephemeral_message_id", 0); + 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_str = chat_id.str(), receiver_user_id, ephemeral_message_id, + input_message_content = std::move(input_message_content)](object_ptr reply_markup, + PromisedQueryPtr query) mutable { + check_chat( + chat_id_str, AccessRights::Edit, std::move(query), + [this, receiver_user_id, ephemeral_message_id, input_message_content = std::move(input_message_content), + reply_markup = std::move(reply_markup)](int64 chat_id, PromisedQueryPtr query) mutable { + send_request( + make_object(chat_id, receiver_user_id, ephemeral_message_id, + std::move(reply_markup), std::move(input_message_content)), + td::make_unique(std::move(query))); + }); + }); + return td::Status::OK(); +} + void Client::abort_long_poll(bool from_set_webhook) { if (long_poll_query_) { td::Slice message; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 3fec71c..60f8acf 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -1044,6 +1044,9 @@ class Client final : public WebhookActor::Callback { void on_sent_story(object_ptr &&story, PromisedQueryPtr query); + td::Status do_edit_ephemeral_message(object_ptr input_message_content, + PromisedQueryPtr &query); + void do_get_file(object_ptr file, PromisedQueryPtr query); bool is_file_being_downloaded(int32 file_id) const; -- cgit v1.2.3 From adfd7f6a8e990272851777eeb3ae0def4216f161 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 14 Jul 2026 14:56:53 +0300 Subject: Update version to 10.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 9bed12b..6cd450d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.10 FATAL_ERROR) -project(TelegramBotApi VERSION 10.1 LANGUAGES CXX) +project(TelegramBotApi VERSION 10.2 LANGUAGES CXX) add_subdirectory(td EXCLUDE_FROM_ALL) diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index 6aa0562..15504b1 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_ = "10.1"; + parameters->version_ = "10.2"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats(); -- cgit v1.2.3