diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f151b7..276606d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 7.1 LANGUAGES CXX) +project(TelegramBotApi VERSION 7.3 LANGUAGES CXX) if (POLICY CMP0069) option(TELEGRAM_BOT_API_ENABLE_LTO "Use \"ON\" to enable Link Time Optimization.") diff --git a/td b/td index d93a99e..af69dd4 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit d93a99e3351db82573d765ce4f5e84714c277518 +Subproject commit af69dd4397b6dc1bf23ba0fd0bf429fcba6454f6 diff --git a/tdlight-api-openapi.yaml b/tdlight-api-openapi.yaml index 7fb7b27..10f0ca5 100644 --- a/tdlight-api-openapi.yaml +++ b/tdlight-api-openapi.yaml @@ -1483,6 +1483,10 @@ paths: query: description: Query to search for. type: string + only_in_channels: + description: Search for messages only in channels + default: false + type: boolean offset_date: description: The date of the message starting from which the results should be fetched. Use 0 or any date in the future to get results from the last message. type: integer @@ -1517,6 +1521,10 @@ paths: query: description: Query to search for. type: string + only_in_channels: + description: Search for messages only in channels + default: false + type: boolean offset_date: description: The date of the message starting from which the results should be fetched. Use 0 or any date in the future to get results from the last message. type: integer @@ -1551,6 +1559,10 @@ paths: query: description: Query to search for. type: string + only_in_channels: + description: Search for messages only in channels + default: false + type: boolean offset_date: description: The date of the message starting from which the results should be fetched. Use 0 or any date in the future to get results from the last message. type: integer diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 2ecb222..2502cdb 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -277,6 +277,7 @@ bool Client::init_methods() { methods_.emplace("createchatinvitelink", &Client::process_create_chat_invite_link_query); methods_.emplace("editchatinvitelink", &Client::process_edit_chat_invite_link_query); methods_.emplace("revokechatinvitelink", &Client::process_revoke_chat_invite_link_query); + methods_.emplace("getbusinessconnection", &Client::process_get_business_connection_query); methods_.emplace("getchat", &Client::process_get_chat_query); methods_.emplace("setchatphoto", &Client::process_set_chat_photo_query); methods_.emplace("deletechatphoto", &Client::process_delete_chat_photo_query); @@ -322,6 +323,7 @@ bool Client::init_methods() { methods_.emplace("uploadstickerfile", &Client::process_upload_sticker_file_query); methods_.emplace("createnewstickerset", &Client::process_create_new_sticker_set_query); methods_.emplace("addstickertoset", &Client::process_add_sticker_to_set_query); + methods_.emplace("replacestickerinset", &Client::process_replace_sticker_in_set_query); methods_.emplace("setstickersettitle", &Client::process_set_sticker_set_title_query); methods_.emplace("setstickersetthumb", &Client::process_set_sticker_set_thumbnail_query); methods_.emplace("setstickersetthumbnail", &Client::process_set_sticker_set_thumbnail_query); @@ -481,6 +483,7 @@ class Client::JsonUser final : public td::Jsonable { object("can_join_groups", td::JsonBool(user_info->can_join_groups)); object("can_read_all_group_messages", td::JsonBool(user_info->can_read_all_group_messages)); object("supports_inline_queries", td::JsonBool(user_info->is_inline_bot)); + object("can_connect_to_business", td::JsonBool(user_info->can_connect_to_business)); } } @@ -618,6 +621,101 @@ class Client::JsonVectorEntities final : public td::Jsonable { const Client *client_; }; +class Client::JsonMaskPosition final : public td::Jsonable { + public: + explicit JsonMaskPosition(const td_api::maskPosition *mask_position) : mask_position_(mask_position) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("point", Client::MASK_POINTS[Client::mask_point_to_index(mask_position_->point_)]); + object("x_shift", mask_position_->x_shift_); + object("y_shift", mask_position_->y_shift_); + object("scale", mask_position_->scale_); + } + + private: + const td_api::maskPosition *mask_position_; +}; + +class Client::JsonSticker final : public td::Jsonable { + public: + JsonSticker(const td_api::sticker *sticker, const Client *client) : sticker_(sticker), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("width", sticker_->width_); + object("height", sticker_->height_); + if (!sticker_->emoji_.empty()) { + object("emoji", sticker_->emoji_); + } + auto set_name = client_->get_sticker_set_name(sticker_->set_id_); + if (!set_name.empty()) { + object("set_name", set_name); + } + + auto format = sticker_->format_->get_id(); + object("is_animated", td::JsonBool(format == td_api::stickerFormatTgs::ID)); + object("is_video", td::JsonBool(format == td_api::stickerFormatWebm::ID)); + + switch (sticker_->full_type_->get_id()) { + case td_api::stickerFullTypeRegular::ID: { + auto full_type = static_cast(sticker_->full_type_.get()); + object("type", Client::get_sticker_type(make_object())); + if (full_type->premium_animation_ != nullptr) { + object("premium_animation", JsonFile(full_type->premium_animation_.get(), client_, false)); + } + break; + } + case td_api::stickerFullTypeMask::ID: { + auto full_type = static_cast(sticker_->full_type_.get()); + object("type", Client::get_sticker_type(make_object())); + if (full_type->mask_position_ != nullptr) { + object("mask_position", JsonMaskPosition(full_type->mask_position_.get())); + } + break; + } + case td_api::stickerFullTypeCustomEmoji::ID: { + auto full_type = static_cast(sticker_->full_type_.get()); + object("type", Client::get_sticker_type(make_object())); + if (full_type->custom_emoji_id_ != 0) { + object("custom_emoji_id", td::to_string(full_type->custom_emoji_id_)); + } + if (full_type->needs_repainting_) { + object("needs_repainting", td::JsonBool(full_type->needs_repainting_)); + } + break; + } + default: + UNREACHABLE(); + break; + } + + client_->json_store_thumbnail(object, sticker_->thumbnail_.get()); + client_->json_store_file(object, sticker_->sticker_.get()); + } + + private: + const td_api::sticker *sticker_; + const Client *client_; +}; + +class Client::JsonStickers final : public td::Jsonable { + public: + JsonStickers(const td::vector> &stickers, const Client *client) + : stickers_(stickers), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto array = scope->enter_array(); + for (auto &sticker : stickers_) { + array << JsonSticker(sticker.get(), client_); + } + } + + private: + const td::vector> &stickers_; + const Client *client_; +}; + class Client::JsonLocation final : public td::Jsonable { public: explicit JsonLocation(const td_api::location *location, double expires_in = 0.0, int32 live_period = 0, @@ -694,6 +792,94 @@ class Client::JsonReactionCount final : public td::Jsonable { const td_api::messageReaction *message_reaction_; }; +class Client::JsonBirthdate final : public td::Jsonable { + public: + explicit JsonBirthdate(const td_api::birthdate *birthdate) : birthdate_(birthdate) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("day", birthdate_->day_); + object("month", birthdate_->month_); + if (birthdate_->year_ != 0) { + object("year", birthdate_->year_); + } + } + + private: + const td_api::birthdate *birthdate_; +}; + +class Client::JsonBusinessStartPage final : public td::Jsonable { + public: + JsonBusinessStartPage(const td_api::businessStartPage *start_page, const Client *client) + : start_page_(start_page), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + if (!start_page_->title_.empty()) { + object("title", start_page_->title_); + } + if (!start_page_->message_.empty()) { + object("message", start_page_->message_); + } + if (start_page_->sticker_ != nullptr) { + object("sticker", JsonSticker(start_page_->sticker_.get(), client_)); + } + } + + private: + const td_api::businessStartPage *start_page_; + const Client *client_; +}; + +class Client::JsonBusinessLocation final : public td::Jsonable { + public: + explicit JsonBusinessLocation(const td_api::businessLocation *business_location) + : business_location_(business_location) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + if (business_location_->location_ != nullptr) { + object("location", JsonLocation(business_location_->location_.get())); + } + object("address", business_location_->address_); + } + + private: + const td_api::businessLocation *business_location_; +}; + +class Client::JsonBusinessOpeningHoursInterval final : public td::Jsonable { + public: + explicit JsonBusinessOpeningHoursInterval(const td_api::businessOpeningHoursInterval *opening_hours_interval) + : opening_hours_interval_(opening_hours_interval) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("opening_minute", opening_hours_interval_->start_minute_); + object("closing_minute", opening_hours_interval_->end_minute_); + } + + private: + const td_api::businessOpeningHoursInterval *opening_hours_interval_; +}; + +class Client::JsonBusinessOpeningHours final : public td::Jsonable { + public: + explicit JsonBusinessOpeningHours(const td_api::businessOpeningHours *opening_hours) : opening_hours_(opening_hours) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("opening_hours", td::json_array(opening_hours_->opening_hours_, [](const auto &opening_hours_interval) { + return JsonBusinessOpeningHoursInterval(opening_hours_interval.get()); + })); + object("time_zone_name", opening_hours_->time_zone_id_); + } + + private: + const td_api::businessOpeningHours *opening_hours_; +}; + class Client::JsonChatPermissions final : public td::Jsonable { public: explicit JsonChatPermissions(const td_api::chatPermissions *chat_permissions) : chat_permissions_(chat_permissions) { @@ -852,6 +1038,24 @@ class Client::JsonChat final : public td::Jsonable { if (user_info->has_restricted_voice_and_video_messages) { object("has_restricted_voice_and_video_messages", td::JsonTrue()); } + if (user_info->business_info != nullptr) { + auto business_info = user_info->business_info.get(); + if (business_info->start_page_ != nullptr) { + object("business_intro", JsonBusinessStartPage(business_info->start_page_.get(), client_)); + } + if (business_info->location_ != nullptr) { + object("business_location", JsonBusinessLocation(business_info->location_.get())); + } + if (business_info->opening_hours_ != nullptr) { + object("business_opening_hours", JsonBusinessOpeningHours(business_info->opening_hours_.get())); + } + } + if (user_info->birthdate != nullptr) { + object("birthdate", JsonBirthdate(user_info->birthdate.get())); + } + if (user_info->personal_chat_id != 0) { + object("personal_chat", JsonChat(user_info->personal_chat_id, client_)); + } } photo = user_info->photo.get(); break; @@ -1031,6 +1235,7 @@ class Client::JsonChat final : public td::Jsonable { td::json_array(chat_info->available_reactions->reactions_, [](const auto &reaction) { return JsonReactionType(reaction.get()); })); } + object("max_reaction_count", chat_info->max_reaction_count); CHECK(chat_info->accent_color_id != -1); object("accent_color_id", chat_info->accent_color_id); if (chat_info->background_custom_emoji_id != 0) { @@ -1179,8 +1384,8 @@ class Client::JsonMessages final : public td::Jsonable { class Client::JsonLinkPreviewOptions final : public td::Jsonable { public: - JsonLinkPreviewOptions(const td_api::linkPreviewOptions *link_preview_options, const Client *client) - : link_preview_options_(link_preview_options), client_(client) { + explicit JsonLinkPreviewOptions(const td_api::linkPreviewOptions *link_preview_options) + : link_preview_options_(link_preview_options) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); @@ -1203,7 +1408,6 @@ class Client::JsonLinkPreviewOptions final : public td::Jsonable { private: const td_api::linkPreviewOptions *link_preview_options_; - const Client *client_; }; class Client::JsonAnimation final : public td::Jsonable { @@ -1351,101 +1555,6 @@ class Client::JsonChatPhoto final : public td::Jsonable { const Client *client_; }; -class Client::JsonMaskPosition final : public td::Jsonable { - public: - explicit JsonMaskPosition(const td_api::maskPosition *mask_position) : mask_position_(mask_position) { - } - void store(td::JsonValueScope *scope) const { - auto object = scope->enter_object(); - object("point", Client::MASK_POINTS[Client::mask_point_to_index(mask_position_->point_)]); - object("x_shift", mask_position_->x_shift_); - object("y_shift", mask_position_->y_shift_); - object("scale", mask_position_->scale_); - } - - private: - const td_api::maskPosition *mask_position_; -}; - -class Client::JsonSticker final : public td::Jsonable { - public: - JsonSticker(const td_api::sticker *sticker, const Client *client) : sticker_(sticker), client_(client) { - } - void store(td::JsonValueScope *scope) const { - auto object = scope->enter_object(); - object("width", sticker_->width_); - object("height", sticker_->height_); - if (!sticker_->emoji_.empty()) { - object("emoji", sticker_->emoji_); - } - auto set_name = client_->get_sticker_set_name(sticker_->set_id_); - if (!set_name.empty()) { - object("set_name", set_name); - } - - auto format = sticker_->format_->get_id(); - object("is_animated", td::JsonBool(format == td_api::stickerFormatTgs::ID)); - object("is_video", td::JsonBool(format == td_api::stickerFormatWebm::ID)); - - switch (sticker_->full_type_->get_id()) { - case td_api::stickerFullTypeRegular::ID: { - auto full_type = static_cast(sticker_->full_type_.get()); - object("type", Client::get_sticker_type(make_object())); - if (full_type->premium_animation_ != nullptr) { - object("premium_animation", JsonFile(full_type->premium_animation_.get(), client_, false)); - } - break; - } - case td_api::stickerFullTypeMask::ID: { - auto full_type = static_cast(sticker_->full_type_.get()); - object("type", Client::get_sticker_type(make_object())); - if (full_type->mask_position_ != nullptr) { - object("mask_position", JsonMaskPosition(full_type->mask_position_.get())); - } - break; - } - case td_api::stickerFullTypeCustomEmoji::ID: { - auto full_type = static_cast(sticker_->full_type_.get()); - object("type", Client::get_sticker_type(make_object())); - if (full_type->custom_emoji_id_ != 0) { - object("custom_emoji_id", td::to_string(full_type->custom_emoji_id_)); - } - if (full_type->needs_repainting_) { - object("needs_repainting", td::JsonBool(full_type->needs_repainting_)); - } - break; - } - default: - UNREACHABLE(); - break; - } - - client_->json_store_thumbnail(object, sticker_->thumbnail_.get()); - client_->json_store_file(object, sticker_->sticker_.get()); - } - - private: - const td_api::sticker *sticker_; - const Client *client_; -}; - -class Client::JsonStickers final : public td::Jsonable { - public: - JsonStickers(const td::vector> &stickers, const Client *client) - : stickers_(stickers), client_(client) { - } - void store(td::JsonValueScope *scope) const { - auto array = scope->enter_array(); - for (auto &sticker : stickers_) { - array << JsonSticker(sticker.get(), client_); - } - } - - private: - const td::vector> &stickers_; - const Client *client_; -}; - class Client::JsonVideo final : public td::Jsonable { public: JsonVideo(const td_api::video *video, const Client *client) : video_(video), client_(client) { @@ -1623,17 +1732,21 @@ class Client::JsonInvoice final : public td::Jsonable { class Client::JsonPollOption final : public td::Jsonable { public: - explicit JsonPollOption(const td_api::pollOption *option) : option_(option) { + JsonPollOption(const td_api::pollOption *option, const Client *client) : option_(option), client_(client) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("text", option_->text_); + object("text", option_->text_->text_); + if (!option_->text_->entities_.empty()) { + object("text_entities", JsonVectorEntities(option_->text_->entities_, client_)); + } object("voter_count", option_->voter_count_); // ignore is_chosen } private: const td_api::pollOption *option_; + const Client *client_; }; class Client::JsonPoll final : public td::Jsonable { @@ -1643,8 +1756,13 @@ class Client::JsonPoll final : public td::Jsonable { void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); object("id", td::to_string(poll_->id_)); - object("question", poll_->question_); - object("options", td::json_array(poll_->options_, [](auto &option) { return JsonPollOption(option.get()); })); + object("question", poll_->question_->text_); + if (!poll_->question_->entities_.empty()) { + object("question_entities", JsonVectorEntities(poll_->question_->entities_, client_)); + } + object("options", td::json_array(poll_->options_, [client = client_](auto &option) { + return JsonPollOption(option.get(), client); + })); object("total_voter_count", poll_->total_voter_count_); if (poll_->open_period_ != 0 && poll_->close_date_ != 0) { object("open_period", poll_->open_period_); @@ -1731,6 +1849,128 @@ class Client::JsonStory final : public td::Jsonable { const Client *client_; }; +class Client::JsonBackgroundFill final : public td::Jsonable { + public: + explicit JsonBackgroundFill(const td_api::BackgroundFill *background_fill) : background_fill_(background_fill) { + } + void store(td::JsonValueScope *scope) const { + CHECK(background_fill_ != nullptr); + auto object = scope->enter_object(); + switch (background_fill_->get_id()) { + case td_api::backgroundFillSolid::ID: { + auto fill = static_cast(background_fill_); + object("type", "solid"); + object("color", fill->color_); + break; + } + case td_api::backgroundFillGradient::ID: { + auto fill = static_cast(background_fill_); + object("type", "gradient"); + object("top_color", fill->top_color_); + object("bottom_color", fill->bottom_color_); + object("rotation_angle", fill->rotation_angle_); + break; + } + case td_api::backgroundFillFreeformGradient::ID: { + auto fill = static_cast(background_fill_); + object("type", "freeform_gradient"); + object("colors", td::json_array(fill->colors_, [](int32 color) { return color; })); + break; + } + default: + UNREACHABLE(); + } + } + + private: + const td_api::BackgroundFill *background_fill_; +}; + +class Client::JsonBackgroundType final : public td::Jsonable { + public: + JsonBackgroundType(const td_api::BackgroundType *background_type, const td_api::document *document, + int32 dark_theme_dimming, const Client *client) + : background_type_(background_type) + , document_(document) + , dark_theme_dimming_(dark_theme_dimming) + , client_(client) { + } + void store(td::JsonValueScope *scope) const { + CHECK(background_type_ != nullptr); + auto object = scope->enter_object(); + switch (background_type_->get_id()) { + case td_api::backgroundTypeWallpaper::ID: { + auto type = static_cast(background_type_); + object("type", "wallpaper"); + CHECK(document_ != nullptr); + object("document", JsonDocument(document_, client_)); + object("dark_theme_dimming", dark_theme_dimming_); + if (type->is_blurred_) { + object("is_blurred", td::JsonTrue()); + } + if (type->is_moving_) { + object("is_moving", td::JsonTrue()); + } + break; + } + case td_api::backgroundTypePattern::ID: { + auto type = static_cast(background_type_); + object("type", "pattern"); + CHECK(document_ != nullptr); + object("document", JsonDocument(document_, client_)); + object("fill", JsonBackgroundFill(type->fill_.get())); + object("intensity", type->intensity_); + if (type->is_inverted_) { + object("is_inverted", td::JsonTrue()); + } + if (type->is_moving_) { + object("is_moving", td::JsonTrue()); + } + break; + } + case td_api::backgroundTypeFill::ID: { + auto type = static_cast(background_type_); + object("type", "fill"); + object("fill", JsonBackgroundFill(type->fill_.get())); + object("dark_theme_dimming", dark_theme_dimming_); + break; + } + case td_api::backgroundTypeChatTheme::ID: { + auto type = static_cast(background_type_); + object("type", "chat_theme"); + object("theme_name", type->theme_name_); + break; + } + default: + UNREACHABLE(); + } + } + + private: + const td_api::BackgroundType *background_type_; + const td_api::document *document_; + int32 dark_theme_dimming_; + const Client *client_; +}; + +class Client::JsonChatBackground final : public td::Jsonable { + public: + JsonChatBackground(const td_api::chatBackground *chat_background, const Client *client) + : chat_background_(chat_background), client_(client) { + } + void store(td::JsonValueScope *scope) const { + CHECK(chat_background_ != nullptr); + auto object = scope->enter_object(); + auto background = chat_background_->background_.get(); + object("type", JsonBackgroundType(background->type_.get(), background->document_.get(), + chat_background_->dark_theme_dimming_, client_)); + } + + private: + const td_api::chatBackground *chat_background_; + const Client *client_; +}; + class Client::JsonForumTopicCreated final : public td::Jsonable { public: explicit JsonForumTopicCreated(const td_api::messageForumTopicCreated *forum_topic_created) @@ -2085,7 +2325,7 @@ class Client::JsonUserShared final : public td::Jsonable { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("user_id", users_shared_->user_ids_[0]); + object("user_id", users_shared_->users_[0]->user_id_); object("request_id", users_shared_->button_id_); } @@ -2093,32 +2333,75 @@ class Client::JsonUserShared final : public td::Jsonable { const td_api::messageUsersShared *users_shared_; }; +class Client::JsonSharedUser final : public td::Jsonable { + public: + JsonSharedUser(const td_api::sharedUser *shared_user, const Client *client) + : shared_user_(shared_user), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("user_id", shared_user_->user_id_); + if (!shared_user_->first_name_.empty()) { + object("first_name", shared_user_->first_name_); + } + if (!shared_user_->last_name_.empty()) { + object("last_name", shared_user_->last_name_); + } + if (!shared_user_->username_.empty()) { + object("username", shared_user_->username_); + } + if (shared_user_->photo_ != nullptr) { + object("photo", JsonPhoto(shared_user_->photo_.get(), client_)); + } + } + + private: + const td_api::sharedUser *shared_user_; + const Client *client_; +}; + class Client::JsonUsersShared final : public td::Jsonable { public: - explicit JsonUsersShared(const td_api::messageUsersShared *users_shared) : users_shared_(users_shared) { + JsonUsersShared(const td_api::messageUsersShared *users_shared, const Client *client) + : users_shared_(users_shared), client_(client) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("user_ids", td::json_array(users_shared_->user_ids_, [](int64 user_id) { return user_id; })); + object("user_ids", td::json_array(users_shared_->users_, [](auto &user) { return user->user_id_; })); + object("users", td::json_array(users_shared_->users_, + [client = client_](auto &user) { return JsonSharedUser(user.get(), client); })); object("request_id", users_shared_->button_id_); } private: const td_api::messageUsersShared *users_shared_; + const Client *client_; }; class Client::JsonChatShared final : public td::Jsonable { public: - explicit JsonChatShared(const td_api::messageChatShared *chat_shared) : chat_shared_(chat_shared) { + JsonChatShared(const td_api::messageChatShared *chat_shared, const Client *client) + : chat_shared_(chat_shared), client_(client) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("chat_id", chat_shared_->chat_id_); + auto *shared_chat = chat_shared_->chat_.get(); + object("chat_id", shared_chat->chat_id_); + if (!shared_chat->title_.empty()) { + object("title", shared_chat->title_); + } + if (!shared_chat->username_.empty()) { + object("username", shared_chat->username_); + } + if (shared_chat->photo_ != nullptr) { + object("photo", JsonPhoto(shared_chat->photo_.get(), client_)); + } object("request_id", chat_shared_->button_id_); } private: const td_api::messageChatShared *chat_shared_; + const Client *client_; }; class Client::JsonGiveaway final : public td::Jsonable { @@ -2223,7 +2506,7 @@ class Client::JsonGiveawayCompleted final : public td::Jsonable { class Client::JsonChatBoostAdded final : public td::Jsonable { public: - JsonChatBoostAdded(const td_api::messageChatBoost *chat_boost) : chat_boost_(chat_boost) { + explicit JsonChatBoostAdded(const td_api::messageChatBoost *chat_boost) : chat_boost_(chat_boost) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); @@ -2378,7 +2661,7 @@ class Client::JsonExternalReplyInfo final : public td::Jsonable { case td_api::messageText::ID: { auto content = static_cast(reply_->content_.get()); if (content->link_preview_options_ != nullptr) { - object("link_preview_options", JsonLinkPreviewOptions(content->link_preview_options_.get(), client_)); + object("link_preview_options", JsonLinkPreviewOptions(content->link_preview_options_.get())); } break; } @@ -2518,6 +2801,12 @@ class Client::JsonTextQuote final : public td::Jsonable { void Client::JsonMessage::store(td::JsonValueScope *scope) const { CHECK(message_ != nullptr); auto object = scope->enter_object(); + if (!message_->business_connection_id.empty()) { + object("business_connection_id", message_->business_connection_id); + if (message_->sender_business_bot_user_id != 0) { + object("sender_business_bot", JsonUser(message_->sender_business_bot_user_id, client_)); + } + } if (message_->is_scheduled) { object("message_id", as_scheduled_message_id(message_->id)); } else { @@ -2601,7 +2890,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { auto reply_to_message_id = get_same_chat_reply_to_message_id(message_); if (reply_to_message_id > 0) { // internal reply - const MessageInfo *reply_to_message = client_->get_message(message_->chat_id, reply_to_message_id, true); + const MessageInfo *reply_to_message = !message_->business_connection_id.empty() + ? message_->business_reply_to_message.get() + : client_->get_message(message_->chat_id, reply_to_message_id, true); if (reply_to_message != nullptr) { object("reply_to_message", JsonMessage(reply_to_message, false, "reply in " + source_, client_)); } else { @@ -2631,7 +2922,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("entities", JsonVectorEntities(content->text_->entities_, client_)); } if (content->link_preview_options_ != nullptr) { - object("link_preview_options", JsonLinkPreviewOptions(content->link_preview_options_.get(), client_)); + object("link_preview_options", JsonLinkPreviewOptions(content->link_preview_options_.get())); } break; } @@ -2834,7 +3125,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { auto content = static_cast(message_->content.get()); auto message_id = content->message_id_; if (message_id > 0) { - const MessageInfo *pinned_message = client_->get_message(message_->chat_id, message_id, true); + const MessageInfo *pinned_message = !message_->business_connection_id.empty() + ? message_->business_reply_to_message.get() + : client_->get_message(message_->chat_id, message_id, true); if (pinned_message != nullptr) { object("pinned_message", JsonMessage(pinned_message, false, "pin in " + source_, client_)); } else if (need_reply_) { @@ -2944,15 +3237,15 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { } case td_api::messageUsersShared::ID: { auto content = static_cast(message_->content.get()); - if (content->user_ids_.size() == 1) { + if (content->users_.size() == 1) { object("user_shared", JsonUserShared(content)); } - object("users_shared", JsonUsersShared(content)); + object("users_shared", JsonUsersShared(content, client_)); break; } case td_api::messageChatShared::ID: { auto content = static_cast(message_->content.get()); - object("chat_shared", JsonChatShared(content)); + object("chat_shared", JsonChatShared(content, client_)); break; } case td_api::messageStory::ID: { @@ -2960,8 +3253,11 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("story", JsonStory(content->story_sender_chat_id_, content->story_id_, client_)); break; } - case td_api::messageChatSetBackground::ID: + case td_api::messageChatSetBackground::ID: { + auto content = static_cast(message_->content.get()); + object("chat_background_set", JsonChatBackground(content->background_.get(), client_)); break; + } case td_api::messagePremiumGiftCode::ID: break; case td_api::messagePremiumGiveawayCreated::ID: @@ -3002,6 +3298,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { if (message_->is_topic_message) { object("is_topic_message", td::JsonTrue()); } + if (message_->is_from_offline) { + object("is_from_offline", td::JsonTrue()); + } } class Client::JsonMessageId final : public td::Jsonable { @@ -3502,6 +3801,9 @@ class Client::JsonChatMemberUpdated final : public td::Jsonable { if (update_->invite_link_ != nullptr) { object("invite_link", JsonChatInviteLink(update_->invite_link_.get(), client_)); } + if (update_->via_join_request_) { + object("via_join_request", td::JsonTrue()); + } if (update_->via_chat_folder_invite_link_) { object("via_chat_folder_invite_link", td::JsonTrue()); } @@ -3714,6 +4016,43 @@ class Client::JsonMessageReactionCountUpdated final : public td::Jsonable { const Client *client_; }; +class Client::JsonBusinessConnection final : public td::Jsonable { + public: + JsonBusinessConnection(const BusinessConnection *connection, const Client *client) + : connection_(connection), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("id", connection_->id_); + object("user", JsonUser(connection_->user_id_, client_)); + object("user_chat_id", connection_->user_chat_id_); + object("date", connection_->date_); + object("can_reply", td::JsonBool(connection_->can_reply_)); + object("is_enabled", td::JsonBool(connection_->is_enabled_)); + } + + private: + const BusinessConnection *connection_; + const Client *client_; +}; + +class Client::JsonBusinessMessagesDeleted final : public td::Jsonable { + public: + JsonBusinessMessagesDeleted(const td_api::updateBusinessMessagesDeleted *update, const Client *client) + : update_(update), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("business_connection_id", update_->connection_id_); + object("chat", JsonChat(update_->chat_id_, client_)); + object("message_ids", td::json_array(update_->message_ids_, as_client_message_id)); + } + + private: + const td_api::updateBusinessMessagesDeleted *update_; + const Client *client_; +}; + class Client::JsonUpdateTypes final : public td::Jsonable { public: explicit JsonUpdateTypes(td::uint32 update_types) : update_types_(update_types) { @@ -3792,10 +4131,6 @@ class Client::JsonStickerSet final : public td::Jsonable { client_->json_store_thumbnail(object, sticker_set_->thumbnail_.get()); } - auto format = sticker_set_->sticker_format_->get_id(); - object("is_animated", td::JsonBool(format == td_api::stickerFormatTgs::ID)); - object("is_video", td::JsonBool(format == td_api::stickerFormatWebm::ID)); - auto type = Client::get_sticker_type(sticker_set_->sticker_type_); object("sticker_type", type); object("contains_masks", td::JsonBool(type == "mask")); @@ -4168,6 +4503,29 @@ class Client::TdOnSendMessageCallback final : public TdQueryCallback { PromisedQueryPtr query_; }; +class Client::TdOnSendBusinessMessageCallback final : public TdQueryCallback { + public: + TdOnSendBusinessMessageCallback(Client *client, td::string business_connection_id, PromisedQueryPtr query) + : client_(client), business_connection_id_(std::move(business_connection_id)), query_(std::move(query)) { + } + + void on_result(object_ptr result) final { + if (result->get_id() == td_api::error::ID) { + return fail_query_with_error(std::move(query_), move_object_as(result)); + } + + CHECK(result->get_id() == td_api::businessMessage::ID); + auto message = client_->create_business_message(std::move(business_connection_id_), + move_object_as(result)); + answer_query(JsonMessage(message.get(), true, "sent business message", client_), std::move(query_)); + } + + private: + Client *client_; + td::string business_connection_id_; + PromisedQueryPtr query_; +}; + class Client::TdOnSendMessageAlbumCallback final : public TdQueryCallback { public: TdOnSendMessageAlbumCallback(Client *client, int64 chat_id, std::size_t message_count, PromisedQueryPtr query) @@ -4198,6 +4556,34 @@ class Client::TdOnSendMessageAlbumCallback final : public TdQueryCallback { PromisedQueryPtr query_; }; +class Client::TdOnSendBusinessMessageAlbumCallback final : public TdQueryCallback { + public: + TdOnSendBusinessMessageAlbumCallback(Client *client, td::string business_connection_id, PromisedQueryPtr query) + : client_(client), business_connection_id_(std::move(business_connection_id)), query_(std::move(query)) { + } + + void on_result(object_ptr result) final { + if (result->get_id() == td_api::error::ID) { + return fail_query_with_error(std::move(query_), move_object_as(result)); + } + + CHECK(result->get_id() == td_api::businessMessages::ID); + auto messages = move_object_as(result); + td::vector message_strings; + for (auto &message : messages->messages_) { + auto message_info = client_->create_business_message(business_connection_id_, std::move(message)); + message_strings.push_back( + td::json_encode(JsonMessage(message_info.get(), true, "sent business message", client_))); + } + answer_query(JsonMessages(message_strings), std::move(query_)); + } + + private: + Client *client_; + td::string business_connection_id_; + PromisedQueryPtr query_; +}; + class Client::TdOnForwardMessagesCallback final : public TdQueryCallback { public: TdOnForwardMessagesCallback(Client *client, int64 chat_id, std::size_t message_count, PromisedQueryPtr query) @@ -4383,7 +4769,7 @@ class Client::TdOnCheckUserCallback final : public TdQueryCallback { auto user_info = client_->get_user_info(user->id_); CHECK(user_info != nullptr); // it must have already been got through updates - return client_->check_user_read_access(user_info, std::move(query_), std::move(on_success_)); + client_->check_user_read_access(user_info, std::move(query_), std::move(on_success_)); } private: @@ -4434,7 +4820,7 @@ class Client::TdOnCheckChatCallback final : public TdQueryCallback { return fail_query(400, "Bad Request: chat not found", std::move(query_)); } - return client_->check_chat_access(chat->id_, access_rights_, chat_info, std::move(query_), std::move(on_success_)); + client_->check_chat_access(chat->id_, access_rights_, chat_info, std::move(query_), std::move(on_success_)); } private: @@ -4496,6 +4882,30 @@ class Client::TdOnCheckChatNoFailCallback final : public TdQueryCallback { OnSuccess on_success_; }; +template +class Client::TdOnCheckBusinessConnectionCallback final : public TdQueryCallback { + public: + TdOnCheckBusinessConnectionCallback(Client *client, PromisedQueryPtr query, OnSuccess on_success) + : client_(client), query_(std::move(query)), on_success_(std::move(on_success)) { + } + + void on_result(object_ptr result) final { + if (result->get_id() == td_api::error::ID) { + return fail_query_with_error(std::move(query_), move_object_as(result), + "business connection not found"); + } + + CHECK(result->get_id() == td_api::businessConnection::ID); + auto connection = client_->add_business_connection(move_object_as(result), false); + on_success_(connection, std::move(query_)); + } + + private: + Client *client_; + PromisedQueryPtr query_; + OnSuccess on_success_; +}; + template class Client::TdOnSearchStickerSetCallback final : public TdQueryCallback { public: @@ -4836,11 +5246,13 @@ class Client::TdOnGetCallbackQueryMessageCallback final : public TdQueryCallback class Client::TdOnGetStickerSetCallback final : public TdQueryCallback { public: - TdOnGetStickerSetCallback(Client *client, int64 set_id, int64 new_callback_query_user_id, int64 new_message_chat_id) + TdOnGetStickerSetCallback(Client *client, int64 set_id, int64 new_callback_query_user_id, int64 new_message_chat_id, + const td::string &new_message_business_connection_id) : client_(client) , set_id_(set_id) , new_callback_query_user_id_(new_callback_query_user_id) - , new_message_chat_id_(new_message_chat_id) { + , new_message_chat_id_(new_message_chat_id) + , new_message_business_connection_id_(new_message_business_connection_id) { } void on_result(object_ptr result) final { @@ -4851,12 +5263,13 @@ class Client::TdOnGetStickerSetCallback final : public TdQueryCallback { << new_callback_query_user_id_ << "/new message in chat " << new_message_chat_id_ << ": " << td::oneline(to_string(error)); } - return client_->on_get_sticker_set(set_id_, new_callback_query_user_id_, new_message_chat_id_, nullptr); + return client_->on_get_sticker_set(set_id_, new_callback_query_user_id_, new_message_chat_id_, + new_message_business_connection_id_, nullptr); } CHECK(result->get_id() == td_api::stickerSet::ID); client_->on_get_sticker_set(set_id_, new_callback_query_user_id_, new_message_chat_id_, - move_object_as(result)); + new_message_business_connection_id_, move_object_as(result)); } private: @@ -4864,6 +5277,7 @@ class Client::TdOnGetStickerSetCallback final : public TdQueryCallback { int64 set_id_; int64 new_callback_query_user_id_; int64 new_message_chat_id_; + td::string new_message_business_connection_id_; }; class Client::TdOnGetChatCustomEmojiStickerSetCallback final : public TdQueryCallback { @@ -4896,6 +5310,39 @@ class Client::TdOnGetChatCustomEmojiStickerSetCallback final : public TdQueryCal PromisedQueryPtr query_; }; +class Client::TdOnGetChatBusinessStartPageStickerSetCallback final : public TdQueryCallback { + public: + TdOnGetChatBusinessStartPageStickerSetCallback(Client *client, int64 chat_id, int64 pinned_message_id, + PromisedQueryPtr query) + : client_(client), chat_id_(chat_id), pinned_message_id_(pinned_message_id), query_(std::move(query)) { + } + + void on_result(object_ptr result) final { + auto chat_info = client_->get_chat(chat_id_); + CHECK(chat_info != nullptr); + CHECK(chat_info->type == ChatInfo::Type::Private); + auto user_info = client_->add_user_info(chat_info->user_id); + if (result->get_id() == td_api::error::ID) { + if (user_info->business_info != nullptr && user_info->business_info->start_page_ != nullptr && + user_info->business_info->start_page_->sticker_ != nullptr) { + user_info->business_info->start_page_->sticker_->set_id_ = 0; + } + } else { + CHECK(result->get_id() == td_api::stickerSet::ID); + auto sticker_set = move_object_as(result); + client_->on_get_sticker_set_name(sticker_set->id_, sticker_set->name_); + } + + answer_query(JsonChat(chat_id_, client_, true, pinned_message_id_), std::move(query_)); + } + + private: + Client *client_; + int64 chat_id_; + int64 pinned_message_id_; + PromisedQueryPtr query_; +}; + class Client::TdOnGetChatStickerSetCallback final : public TdQueryCallback { public: TdOnGetChatStickerSetCallback(Client *client, int64 chat_id, int64 pinned_message_id, PromisedQueryPtr query) @@ -4974,6 +5421,21 @@ class Client::TdOnGetChatPinnedMessageCallback final : public TdQueryCallback { td::make_unique( client_, chat_id_, pinned_message_id, std::move(query_))); } + } else if (chat_info->type == ChatInfo::Type::Private) { + auto user_info = client_->get_user_info(chat_info->user_id); + CHECK(user_info != nullptr); + + if (user_info->business_info != nullptr && user_info->business_info->start_page_ != nullptr) { + auto *sticker = user_info->business_info->start_page_->sticker_.get(); + if (sticker != nullptr) { + auto sticker_set_id = sticker->set_id_; + if (sticker_set_id != 0 && client_->get_sticker_set_name(sticker_set_id).empty()) { + return client_->send_request(make_object(sticker_set_id), + td::make_unique( + client_, chat_id_, pinned_message_id, std::move(query_))); + } + } + } } answer_query(JsonChat(chat_id_, client_, true, pinned_message_id), std::move(query_)); @@ -5243,7 +5705,7 @@ class Client::TdOnGetSupergroupMemberCountCallback final : public TdQueryCallbac CHECK(result->get_id() == td_api::supergroupFullInfo::ID); auto supergroup_full_info = move_object_as(result); - return answer_query(td::VirtuallyJsonableInt(supergroup_full_info->member_count_), std::move(query_)); + answer_query(td::VirtuallyJsonableInt(supergroup_full_info->member_count_), std::move(query_)); } private: @@ -5262,7 +5724,7 @@ class Client::TdOnCreateInvoiceLinkCallback final : public TdQueryCallback { CHECK(result->get_id() == td_api::httpUrl::ID); auto http_url = move_object_as(result); - return answer_query(td::VirtuallyJsonableString(http_url->url_), std::move(query_)); + answer_query(td::VirtuallyJsonableString(http_url->url_), std::move(query_)); } private: @@ -5281,7 +5743,7 @@ class Client::TdOnReplacePrimaryChatInviteLinkCallback final : public TdQueryCal CHECK(result->get_id() == td_api::chatInviteLink::ID); auto invite_link = move_object_as(result); - return answer_query(td::VirtuallyJsonableString(invite_link->invite_link_), std::move(query_)); + answer_query(td::VirtuallyJsonableString(invite_link->invite_link_), std::move(query_)); } private: @@ -5978,6 +6440,7 @@ void Client::on_get_callback_query_message(object_ptr message, } void Client::on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, int64 new_message_chat_id, + const td::string &new_message_business_connection_id, object_ptr sticker_set) { if (new_callback_query_user_id != 0) { auto &queue = new_callback_query_queues_[new_callback_query_user_id]; @@ -5993,6 +6456,13 @@ void Client::on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, CHECK(!queue.queue_.empty()); } + if (!new_message_business_connection_id.empty()) { + auto &queue = new_business_message_queues_[new_message_business_connection_id]; + CHECK(queue.has_active_request_); + queue.has_active_request_ = false; + + CHECK(!queue.queue_.empty()); + } CHECK(set_id != 0); if (set_id != GREAT_MINDS_SET_ID) { @@ -6008,6 +6478,9 @@ void Client::on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, if (new_message_chat_id != 0) { process_new_message_queue(new_message_chat_id, 2); } + if (!new_message_business_connection_id.empty()) { + process_new_business_message_queue(new_message_business_connection_id); + } } void Client::on_get_sticker_set_name(int64 set_id, const td::string &name) { @@ -6029,7 +6502,7 @@ void Client::check_user_read_access(const UserInfo *user_info, PromisedQueryPtr template void Client::check_user(int64 user_id, PromisedQueryPtr query, OnSuccess on_success) { const UserInfo *user_info = get_user_info(user_id); - if (user_info != nullptr) { + if (user_info != nullptr && user_info->have_access) { return check_user_read_access(user_info, std::move(query), std::move(on_success)); } send_request(make_object(user_id), @@ -6039,7 +6512,7 @@ void Client::check_user(int64 user_id, PromisedQueryPtr query, OnSuccess on_succ template void Client::check_user_no_fail(int64 user_id, PromisedQueryPtr query, OnSuccess on_success) { const UserInfo *user_info = get_user_info(user_id); - if (user_info != nullptr) { + if (user_info != nullptr && user_info->have_access) { on_success(std::move(query)); return; } @@ -6135,6 +6608,12 @@ void Client::check_chat(td::Slice chat_id_str, AccessRights access_rights, Promi auto chat_id = td::to_integer(chat_id_str); auto chat_info = get_chat(chat_id); + if (chat_info != nullptr && chat_info->type == ChatInfo::Type::Private) { + const UserInfo *user_info = get_user_info(chat_info->user_id); + if (user_info == nullptr || !user_info->have_access) { + chat_info = nullptr; + } + } if (chat_info != nullptr) { return check_chat_access(chat_id, access_rights, chat_info, std::move(query), std::move(on_success)); } @@ -6156,6 +6635,12 @@ void Client::check_chat_no_fail(td::Slice chat_id_str, PromisedQueryPtr query, O auto chat_id = r_chat_id.move_as_ok(); auto chat_info = get_chat(chat_id); + if (chat_info != nullptr && chat_info->type == ChatInfo::Type::Private) { + const UserInfo *user_info = get_user_info(chat_info->user_id); + if (user_info == nullptr || !user_info->have_access) { + chat_info = nullptr; + } + } if (chat_info != nullptr) { return on_success(chat_id, std::move(query)); } @@ -6163,6 +6648,30 @@ void Client::check_chat_no_fail(td::Slice chat_id_str, PromisedQueryPtr query, O chat_id, std::move(query), std::move(on_success))); } +td::Result Client::get_business_connection_chat_id(td::Slice chat_id_str) { + if (chat_id_str.empty()) { + return td::Status::Error(400, "Bad Request: chat_id is empty"); + } + + auto r_chat_id = td::to_integer_safe(chat_id_str); + if (r_chat_id.is_error()) { + return td::Status::Error(400, "Bad Request: chat_id must be a valid Integer"); + } + return r_chat_id.move_as_ok(); +} + +template +void Client::check_business_connection(const td::string &business_connection_id, PromisedQueryPtr query, + OnSuccess on_success) { + auto business_connection = get_business_connection(business_connection_id); + if (business_connection != nullptr) { + return on_success(business_connection, std::move(query)); + } + send_request( + make_object(business_connection_id), + td::make_unique>(this, std::move(query), std::move(on_success))); +} + template void Client::check_bot_command_scope(BotCommandScope &&scope, PromisedQueryPtr query, OnSuccess on_success) { CHECK(scope.scope_ != nullptr); @@ -6299,7 +6808,7 @@ void Client::check_reply_parameters(td::Slice chat_id_str, InputReplyParameters } if (message_thread_id <= 0) { - // if message thread isn't specified, then the message to reply can be only from a different chat + // if message thread isn't specified, then the message to be replied can be only from a different chat if (reply_parameters.reply_in_chat_id == chat_id) { reply_parameters.reply_in_chat_id = 0; } @@ -6329,13 +6838,13 @@ void Client::check_reply_parameters(td::Slice chat_id_str, InputReplyParameters on_success = std::move(on_reply_message_resolved)]( int64 reply_in_chat_id, PromisedQueryPtr query) mutable { if (!have_message_access(reply_in_chat_id)) { - return fail_query_with_error(std::move(query), 400, "MESSAGE_NOT_FOUND", "message to reply not found"); + return fail_query_with_error(std::move(query), 400, "MESSAGE_NOT_FOUND", "message to be replied not found"); } send_request(make_object(reply_in_chat_id, reply_to_message_id), td::make_unique>( - this, reply_in_chat_id, reply_to_message_id, allow_sending_without_reply, "message to reply", - std::move(query), std::move(on_success))); + this, reply_in_chat_id, reply_to_message_id, allow_sending_without_reply, + "message to be replied", std::move(query), std::move(on_success))); }; if (reply_parameters.reply_in_chat_id.empty()) { return on_reply_chat_resolved(chat_id, std::move(query)); @@ -6776,9 +7285,7 @@ void Client::on_update(object_ptr result) { chat->emoji_status_ != nullptr ? chat->emoji_status_->custom_emoji_id_ : 0; chat_info->emoji_status_expiration_date = chat->emoji_status_ != nullptr ? chat->emoji_status_->expiration_date_ : 0; - if (chat->available_reactions_->get_id() == td_api::chatAvailableReactionsSome::ID) { - chat_info->available_reactions = move_object_as(chat->available_reactions_); - } + set_chat_available_reactions(chat_info, std::move(chat->available_reactions_)); chat_info->accent_color_id = chat->accent_color_id_; chat_info->background_custom_emoji_id = chat->background_custom_emoji_id_; chat_info->profile_accent_color_id = chat->profile_accent_color_id_; @@ -6828,12 +7335,7 @@ void Client::on_update(object_ptr result) { auto update = move_object_as(result); auto chat_info = add_chat(update->chat_id_); CHECK(chat_info->type != ChatInfo::Type::Unknown); - if (update->available_reactions_->get_id() == td_api::chatAvailableReactionsSome::ID) { - chat_info->available_reactions = - move_object_as(update->available_reactions_); - } else { - chat_info->available_reactions = nullptr; - } + set_chat_available_reactions(chat_info, std::move(update->available_reactions_)); break; } case td_api::updateChatAccentColors::ID: { @@ -6867,6 +7369,9 @@ void Client::on_update(object_ptr result) { user_info->photo = full_info->photo_ == nullptr ? std::move(full_info->public_photo_) : std::move(full_info->photo_); user_info->bio = full_info->bio_ != nullptr ? std::move(full_info->bio_->text_) : td::string(); + user_info->birthdate = std::move(full_info->birthdate_); + user_info->business_info = std::move(full_info->business_info_); + user_info->personal_chat_id = full_info->personal_chat_id_; user_info->has_private_forwards = full_info->has_private_forwards_; user_info->has_restricted_voice_and_video_messages = full_info->has_restricted_voice_and_video_note_messages_; break; @@ -6890,8 +7395,8 @@ void Client::on_update(object_ptr result) { auto group_info = add_group_info(group_id); group_info->photo = std::move(full_info->photo_); group_info->description = std::move(full_info->description_); - group_info->invite_link = std::move( - full_info->invite_link_ != nullptr ? std::move(full_info->invite_link_->invite_link_) : td::string()); + group_info->invite_link = + full_info->invite_link_ != nullptr ? std::move(full_info->invite_link_->invite_link_) : td::string(); break; } case td_api::updateSupergroup::ID: { @@ -6907,8 +7412,8 @@ void Client::on_update(object_ptr result) { auto supergroup_info = add_supergroup_info(supergroup_id); supergroup_info->photo = std::move(full_info->photo_); supergroup_info->description = std::move(full_info->description_); - supergroup_info->invite_link = std::move( - full_info->invite_link_ != nullptr ? std::move(full_info->invite_link_->invite_link_) : td::string()); + supergroup_info->invite_link = + full_info->invite_link_ != nullptr ? std::move(full_info->invite_link_->invite_link_) : td::string(); supergroup_info->sticker_set_id = full_info->sticker_set_id_; supergroup_info->custom_emoji_sticker_set_id = full_info->custom_emoji_sticker_set_id_; supergroup_info->can_set_sticker_set = full_info->can_set_sticker_set_; @@ -7022,6 +7527,18 @@ void Client::on_update(object_ptr result) { case td_api::updateMessageReactions::ID: add_update_message_reaction_count(move_object_as(result)); break; + case td_api::updateBusinessConnection::ID: + add_update_business_connection(move_object_as(result)); + break; + case td_api::updateNewBusinessMessage::ID: + add_new_business_message(move_object_as(result)); + break; + case td_api::updateBusinessMessageEdited::ID: + add_business_message_edited(move_object_as(result)); + break; + case td_api::updateBusinessMessagesDeleted::ID: + add_update_business_messages_deleted(move_object_as(result)); + break; case td_api::updateConnectionState::ID: { auto update = move_object_as(result); if (update->state_->get_id() == td_api::connectionStateReady::ID) { @@ -7176,6 +7693,15 @@ td_api::object_ptr Client::get_input_message_reply_ return nullptr; } +td_api::object_ptr Client::get_input_message_reply_to( + InputReplyParameters &&reply_parameters) { + if (reply_parameters.reply_in_chat_id.empty() && reply_parameters.reply_to_message_id > 0) { + return make_object(0, reply_parameters.reply_to_message_id, + std::move(reply_parameters.quote)); + } + return nullptr; +} + td::Result Client::get_reply_parameters(const Query *query) { if (!query->has_arg("reply_parameters")) { InputReplyParameters result; @@ -7279,9 +7805,13 @@ td::Result> Client::get_keyboard_butt auto restrict_user_is_premium = request_user_object.has_field("user_is_premium"); TRY_RESULT(user_is_premium, request_user_object.get_optional_bool_field("user_is_premium")); TRY_RESULT(max_quantity, request_user_object.get_optional_int_field("max_quantity", 1)); + TRY_RESULT(request_name, request_user_object.get_optional_bool_field("request_name")); + TRY_RESULT(request_username, request_user_object.get_optional_bool_field("request_username")); + TRY_RESULT(request_photo, request_user_object.get_optional_bool_field("request_photo")); return make_object( text, make_object( - id, restrict_user_is_bot, user_is_bot, restrict_user_is_premium, user_is_premium, max_quantity)); + id, restrict_user_is_bot, user_is_bot, restrict_user_is_premium, user_is_premium, max_quantity, + request_name, request_username, request_photo)); } if (object.has_field("request_chat")) { @@ -7306,11 +7836,15 @@ td::Result> Client::get_keyboard_butt get_chat_administrator_rights(request_chat_object.extract_field("bot_administrator_rights"))); } TRY_RESULT(bot_is_member, request_chat_object.get_optional_bool_field("bot_is_member")); + TRY_RESULT(request_title, request_chat_object.get_optional_bool_field("request_title")); + TRY_RESULT(request_username, request_chat_object.get_optional_bool_field("request_username")); + TRY_RESULT(request_photo, request_chat_object.get_optional_bool_field("request_photo")); return make_object( - text, make_object( - id, chat_is_channel, restrict_chat_is_forum, chat_is_forum, restrict_chat_has_username, - chat_has_username, chat_is_created, std::move(user_administrator_rights), - std::move(bot_administrator_rights), bot_is_member)); + text, + make_object( + id, chat_is_channel, restrict_chat_is_forum, chat_is_forum, restrict_chat_has_username, chat_has_username, + chat_is_created, std::move(user_administrator_rights), std::move(bot_administrator_rights), bot_is_member, + request_title, request_username, request_photo)); } return make_object(text, nullptr); @@ -8607,11 +9141,15 @@ td::Result> Client::get_sticker_format if (sticker_format == "video") { return make_object(); } + if (sticker_format == "auto") { + return nullptr; + } return td::Status::Error(400, "Invalid sticker format specified"); } td::Result> Client::get_input_sticker(const Query *query, - td::JsonValue &&value) const { + td::JsonValue &&value, + td::Slice default_sticker_format) const { if (value.type() != td::JsonValue::Type::Object) { return td::Status::Error(400, "InputSticker must be an Object"); } @@ -8623,6 +9161,16 @@ td::Result> Client::get_input_sticker(c if (input_file == nullptr) { return td::Status::Error(400, "sticker not found"); } + td::string sticker_format_str; + if (default_sticker_format.empty()) { + TRY_RESULT_ASSIGN(sticker_format_str, object.get_required_string_field("format")); + } else { + TRY_RESULT_ASSIGN(sticker_format_str, object.get_optional_string_field("format")); + if (sticker_format_str.empty()) { + sticker_format_str = default_sticker_format.str(); + } + } + TRY_RESULT(sticker_format, get_sticker_format(sticker_format_str)); TRY_RESULT(emoji_list, object.extract_required_field("emoji_list", td::JsonValue::Type::Array)); TRY_RESULT(emojis, get_sticker_emojis(std::move(emoji_list))); TRY_RESULT(mask_position, get_mask_position(object.extract_field("mask_position"))); @@ -8636,8 +9184,8 @@ td::Result> Client::get_input_sticker(c input_keywords.push_back(keyword.get_string().str()); } } - return make_object(std::move(input_file), emojis, std::move(mask_position), - std::move(input_keywords)); + return make_object(std::move(input_file), std::move(sticker_format), emojis, + std::move(mask_position), std::move(input_keywords)); } td::Result> Client::get_input_sticker(const Query *query) const { @@ -8650,75 +9198,20 @@ td::Result> Client::get_input_sticker(c return td::Status::Error(400, "Can't parse sticker JSON object"); } - auto r_sticker = get_input_sticker(query, r_value.move_as_ok()); + auto r_sticker = get_input_sticker(query, r_value.move_as_ok(), "auto"); if (r_sticker.is_error()) { return td::Status::Error(400, PSLICE() << "Can't parse sticker: " << r_sticker.error().message()); } return r_sticker.move_as_ok(); } - auto emojis = query->arg("emojis"); - - auto sticker = get_input_file(query, "png_sticker"); - object_ptr mask_position; - if (sticker != nullptr) { - TRY_RESULT_ASSIGN(mask_position, get_mask_position(query, "mask_position")); - } else { - sticker = get_input_file(query, "tgs_sticker", true); - if (sticker == nullptr) { - sticker = get_input_file(query, "webm_sticker", true); - if (sticker == nullptr) { - if (!query->arg("tgs_sticker").empty()) { - return td::Status::Error(400, "Bad Request: animated sticker must be uploaded as an InputFile"); - } - if (!query->arg("webm_sticker").empty()) { - return td::Status::Error(400, "Bad Request: video sticker must be uploaded as an InputFile"); - } - return td::Status::Error(400, "Bad Request: there is no sticker file in the request"); - } - } - } - - return make_object(std::move(sticker), emojis.str(), std::move(mask_position), - td::vector()); + return get_legacy_input_sticker(query); } -td::Result>> Client::get_input_stickers( - const Query *query, object_ptr &sticker_format) const { - if (query->has_arg("stickers")) { - TRY_RESULT_ASSIGN(sticker_format, get_sticker_format(query->arg("sticker_format"))); - auto stickers = query->arg("stickers"); - LOG(INFO) << "Parsing JSON object: " << stickers; - auto r_value = json_decode(stickers); - if (r_value.is_error()) { - 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> input_stickers; - for (auto &input_sticker : value.get_array()) { - auto r_input_sticker = get_input_sticker(query, std::move(input_sticker)); - if (r_input_sticker.is_error()) { - return td::Status::Error(400, PSLICE() << "Can't parse InputSticker: " << r_input_sticker.error().message()); - } - input_stickers.push_back(r_input_sticker.move_as_ok()); - } - return std::move(input_stickers); - } - +td::Result> Client::get_legacy_input_sticker(const Query *query) const { auto emojis = query->arg("emojis"); - auto sticker = get_input_file(query, "png_sticker"); + object_ptr sticker_format; object_ptr mask_position; if (sticker != nullptr) { sticker_format = make_object(); @@ -8743,14 +9236,52 @@ td::Result>> Client::get_inp } } + 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 { + if (query->has_arg("stickers")) { + auto sticker_format_str = query->arg("sticker_format"); + auto stickers = query->arg("stickers"); + LOG(INFO) << "Parsing JSON object: " << stickers; + auto r_value = json_decode(stickers); + if (r_value.is_error()) { + 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> 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()); + } + input_stickers.push_back(r_input_sticker.move_as_ok()); + } + return std::move(input_stickers); + } + + TRY_RESULT(input_sticker, get_legacy_input_sticker(query)); + td::vector> stickers; - stickers.push_back(make_object(std::move(sticker), emojis.str(), std::move(mask_position), - td::vector())); + stickers.push_back(std::move(input_sticker)); return std::move(stickers); } -td::Result> Client::get_sticker_input_file(const Query *query) { - auto file_id = trim(query->arg("sticker")); +td::Result> Client::get_sticker_input_file(const Query *query, + td::Slice field_name) { + auto file_id = trim(query->arg(field_name)); if (file_id.empty()) { return td::Status::Error(400, "Sticker is not specified"); } @@ -9411,7 +9942,7 @@ td::Result> Client::get_input_me provider_token.str(), provider_data.str(), start_parameter.str(), std::move(extended_media)); } -td::Result> Client::get_poll_options(const Query *query) { +td::Result>> Client::get_poll_options(const Query *query) { auto input_options = query->arg("options"); LOG(INFO) << "Parsing JSON object: " << input_options; auto r_value = json_decode(input_options); @@ -9425,12 +9956,22 @@ td::Result> Client::get_poll_options(const Query *query) return td::Status::Error(400, "Expected an Array of String as options"); } - td::vector options; + td::vector> options; for (auto &input_option : value.get_array()) { if (input_option.type() != td::JsonValue::Type::String) { + if (input_option.type() == td::JsonValue::Type::Object) { + auto &object = input_option.get_object(); + TRY_RESULT(text, object.get_required_string_field("text")); + TRY_RESULT(parse_mode, object.get_optional_string_field("text_parse_mode")); + TRY_RESULT(option_text, + get_formatted_text(std::move(text), std::move(parse_mode), object.extract_field("text_entities"))); + options.push_back(std::move(option_text)); + continue; + } + return td::Status::Error(400, "Expected an option to be of type String"); } - options.push_back(input_option.get_string().str()); + options.push_back(make_object(input_option.get_string().str(), td::Auto())); } return std::move(options); } @@ -10233,7 +10774,8 @@ td::Status Client::process_send_contact_query(PromisedQueryPtr &query) { } td::Status Client::process_send_poll_query(PromisedQueryPtr &query) { - auto question = query->arg("question"); + TRY_RESULT(question, get_formatted_text(query->arg("question").str(), query->arg("question_parse_mode").str(), + get_input_entities(query.get(), "question_entities"))); TRY_RESULT(options, get_poll_options(query.get())); bool is_anonymous = true; if (query->has_arg("is_anonymous")) { @@ -10257,7 +10799,7 @@ td::Status Client::process_send_poll_query(PromisedQueryPtr &query) { int32 open_period = get_integer_arg(query.get(), "open_period", 0, 0, 10 * 60); int32 close_date = get_integer_arg(query.get(), "close_date", 0); auto is_closed = to_bool(query->arg("is_closed")); - do_send_message(make_object(question.str(), std::move(options), is_anonymous, + do_send_message(make_object(std::move(question), std::move(options), is_anonymous, std::move(poll_type), open_period, close_date, is_closed), std::move(query)); return td::Status::OK(); @@ -10408,6 +10950,7 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); auto message_thread_id = get_message_id(query.get(), "message_thread_id"); TRY_RESULT(reply_parameters, get_reply_parameters(query.get())); + auto business_connection_id = query->arg("business_connection_id"); auto disable_notification = to_bool(query->arg("disable_notification")); auto protect_content = to_bool(query->arg("protect_content")); // TRY_RESULT(reply_markup, get_reply_markup(query.get(), bot_user_ids_)); @@ -10417,10 +10960,31 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, chat_id = chat_id.str(), message_thread_id, reply_parameters = std::move(reply_parameters), + [this, chat_id_str = chat_id.str(), message_thread_id, business_connection_id = business_connection_id.str(), send_at = std::move(send_at), - disable_notification, protect_content, input_message_contents = std::move(input_message_contents)]( - object_ptr reply_markup, PromisedQueryPtr query) mutable { + reply_parameters = std::move(reply_parameters), disable_notification, protect_content, + input_message_contents = std::move(input_message_contents)](object_ptr reply_markup, + PromisedQueryPtr query) mutable { + if (!business_connection_id.empty()) { + auto r_chat_id = get_business_connection_chat_id(chat_id_str); + if (r_chat_id.is_error()) { + return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); + } + auto chat_id = r_chat_id.move_as_ok(); + return check_business_connection( + business_connection_id, std::move(query), + [this, chat_id, reply_parameters = std::move(reply_parameters), disable_notification, protect_content, + input_message_contents = std::move(input_message_contents), reply_markup = std::move(reply_markup)]( + const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { + send_request( + make_object( + business_connection->id_, chat_id, get_input_message_reply_to(std::move(reply_parameters)), + disable_notification, protect_content, std::move(input_message_contents)), + td::make_unique(this, business_connection->id_, + std::move(query))); + }); + } + auto on_success = [this, disable_notification, protect_content, input_message_contents = std::move(input_message_contents), send_at = std::move(send_at), @@ -10440,24 +11004,37 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { get_message_send_options(disable_notification, protect_content, std::move(send_at)), std::move(input_message_contents)), td::make_unique(this, chat_id, message_count, std::move(query))); }; - check_reply_parameters(chat_id, std::move(reply_parameters), message_thread_id, std::move(query), + check_reply_parameters(chat_id_str, std::move(reply_parameters), message_thread_id, std::move(query), std::move(on_success)); }); return td::Status::OK(); } td::Status Client::process_send_chat_action_query(PromisedQueryPtr &query) { - auto chat_id = query->arg("chat_id"); + auto chat_id_str = query->arg("chat_id"); auto message_thread_id = get_message_id(query.get(), "message_thread_id"); + auto business_connection_id = query->arg("business_connection_id").str(); object_ptr action = get_chat_action(query.get()); if (action == nullptr) { return td::Status::Error(400, "Wrong parameter action in request"); } + if (!business_connection_id.empty()) { + TRY_RESULT(chat_id, get_business_connection_chat_id(chat_id_str)); + check_business_connection( + business_connection_id, std::move(query), + [this, chat_id, action = std::move(action)](const BusinessConnection *business_connection, + PromisedQueryPtr query) mutable { + send_request(make_object(chat_id, 0, business_connection->id_, std::move(action)), + td::make_unique(std::move(query))); + }); + return td::Status::OK(); + } - check_chat(chat_id, AccessRights::Write, std::move(query), + check_chat(chat_id_str, AccessRights::Write, std::move(query), [this, message_thread_id, action = std::move(action)](int64 chat_id, PromisedQueryPtr query) mutable { - send_request(make_object(chat_id, message_thread_id, std::move(action)), - td::make_unique(std::move(query))); + send_request( + make_object(chat_id, message_thread_id, td::string(), std::move(action)), + td::make_unique(std::move(query))); }); return td::Status::OK(); } @@ -10515,6 +11092,7 @@ td::Status Client::process_edit_message_text_query(PromisedQueryPtr &query) { td::Status Client::process_edit_message_live_location_query(PromisedQueryPtr &query) { object_ptr location = nullptr; + int32 live_period = get_integer_arg(query.get(), "live_period", 0); int32 heading = get_integer_arg(query.get(), "heading", 0); int32 proximity_alert_radius = get_integer_arg(query.get(), "proximity_alert_radius", 0); if (query->method() == "editmessagelivelocation") { @@ -10529,25 +11107,25 @@ td::Status Client::process_edit_message_live_location_query(PromisedQueryPtr &qu TRY_RESULT(inline_message_id, get_inline_message_id(query.get())); resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, inline_message_id = inline_message_id.str(), location = std::move(location), heading, + [this, inline_message_id = inline_message_id.str(), location = std::move(location), live_period, heading, proximity_alert_radius](object_ptr reply_markup, PromisedQueryPtr query) mutable { - send_request( - make_object(inline_message_id, std::move(reply_markup), - std::move(location), heading, proximity_alert_radius), - td::make_unique(std::move(query))); + send_request(make_object(inline_message_id, std::move(reply_markup), + std::move(location), live_period, heading, + proximity_alert_radius), + td::make_unique(std::move(query))); }); } else { resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, chat_id = chat_id.str(), message_id, location = std::move(location), heading, proximity_alert_radius]( - object_ptr reply_markup, PromisedQueryPtr query) mutable { + [this, chat_id = chat_id.str(), message_id, location = std::move(location), live_period, heading, + proximity_alert_radius](object_ptr reply_markup, PromisedQueryPtr query) mutable { check_message(chat_id, message_id, false, AccessRights::Edit, "message to edit", std::move(query), - [this, location = std::move(location), heading, proximity_alert_radius, + [this, location = std::move(location), live_period, heading, proximity_alert_radius, reply_markup = std::move(reply_markup)](int64 chat_id, int64 message_id, PromisedQueryPtr query) mutable { send_request(make_object( - chat_id, message_id, std::move(reply_markup), std::move(location), heading, - proximity_alert_radius), + chat_id, message_id, std::move(reply_markup), std::move(location), + live_period, heading, proximity_alert_radius), td::make_unique(this, std::move(query))); }); }); @@ -10910,6 +11488,15 @@ td::Status Client::process_revoke_chat_invite_link_query(PromisedQueryPtr &query return td::Status::OK(); } +td::Status Client::process_get_business_connection_query(PromisedQueryPtr &query) { + auto business_connection_id = query->arg("business_connection_id"); + check_business_connection(business_connection_id.str(), std::move(query), + [this](const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { + answer_query(JsonBusinessConnection(business_connection, this), std::move(query)); + }); + return td::Status::OK(); +} + td::Status Client::process_get_chat_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); @@ -11236,7 +11823,7 @@ td::Status Client::process_get_chat_member_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); TRY_RESULT(user_id, get_user_id(query.get())); - check_chat(chat_id, AccessRights::ReadMembers, std::move(query), + check_chat(chat_id, user_id == my_id_ ? AccessRights::Read : AccessRights::ReadMembers, std::move(query), [this, user_id](int64 chat_id, PromisedQueryPtr query) { get_chat_member(chat_id, user_id, std::move(query), [this, chat_type = get_chat_type(chat_id)](object_ptr &&chat_member, @@ -11634,23 +12221,21 @@ td::Status Client::process_create_new_sticker_set_query(PromisedQueryPtr &query) auto name = query->arg("name"); auto title = query->arg("title"); auto needs_repainting = to_bool(query->arg("needs_repainting")); - object_ptr sticker_format; - TRY_RESULT(stickers, get_input_stickers(query.get(), sticker_format)); + TRY_RESULT(stickers, get_input_stickers(query.get())); TRY_RESULT(sticker_type, get_sticker_type(query->arg("sticker_type"))); if (to_bool(query->arg("contains_masks"))) { sticker_type = make_object(); } - check_user( - user_id, std::move(query), - [this, user_id, title, name, sticker_format = std::move(sticker_format), sticker_type = std::move(sticker_type), - needs_repainting, stickers = std::move(stickers)](PromisedQueryPtr query) mutable { - send_request(make_object( - user_id, title.str(), name.str(), std::move(sticker_format), std::move(sticker_type), - needs_repainting, std::move(stickers), PSTRING() << "bot" << my_id_), - td::make_unique(this, false, std::move(query))); - }); + check_user(user_id, std::move(query), + [this, user_id, title, name, sticker_type = std::move(sticker_type), needs_repainting, + stickers = std::move(stickers)](PromisedQueryPtr query) mutable { + send_request(make_object(user_id, title.str(), name.str(), + std::move(sticker_type), needs_repainting, + std::move(stickers), PSTRING() << "bot" << my_id_), + td::make_unique(this, false, std::move(query))); + }); return td::Status::OK(); } @@ -11668,6 +12253,22 @@ td::Status Client::process_add_sticker_to_set_query(PromisedQueryPtr &query) { return td::Status::OK(); } +td::Status Client::process_replace_sticker_in_set_query(PromisedQueryPtr &query) { + TRY_RESULT(user_id, get_user_id(query.get())); + auto name = query->arg("name"); + TRY_RESULT(input_file, get_sticker_input_file(query.get(), "old_sticker")); + TRY_RESULT(sticker, get_input_sticker(query.get())); + + check_user(user_id, std::move(query), + [this, user_id, name, input_file = std::move(input_file), + sticker = std::move(sticker)](PromisedQueryPtr query) mutable { + send_request(make_object(user_id, name.str(), std::move(input_file), + std::move(sticker)), + td::make_unique(std::move(query))); + }); + return td::Status::OK(); +} + td::Status Client::process_set_sticker_set_title_query(PromisedQueryPtr &query) { CHECK_IS_BOT(); auto name = query->arg("name"); @@ -11684,9 +12285,16 @@ td::Status Client::process_set_sticker_set_thumbnail_query(PromisedQueryPtr &que if (thumbnail == nullptr) { thumbnail = get_input_file(query.get(), "thumb"); } + td::Slice sticker_format_str = query->arg("format"); + if (sticker_format_str.empty()) { + sticker_format_str = td::Slice("auto"); + } + TRY_RESULT(sticker_format, get_sticker_format(sticker_format_str)); check_user(user_id, std::move(query), - [this, user_id, name, thumbnail = std::move(thumbnail)](PromisedQueryPtr query) mutable { - send_request(make_object(user_id, name.str(), std::move(thumbnail)), + [this, user_id, name, thumbnail = std::move(thumbnail), + sticker_format = std::move(sticker_format)](PromisedQueryPtr query) mutable { + send_request(make_object(user_id, name.str(), std::move(thumbnail), + std::move(sticker_format)), td::make_unique(std::move(query))); }); return td::Status::OK(); @@ -12253,8 +12861,9 @@ td::Status Client::process_search_messages_query(PromisedQueryPtr &query) { TRY_RESULT(filter, get_search_messages_filter(query.get())); auto min_date = get_integer_arg(query.get(), "min_date", 0); auto max_date = get_integer_arg(query.get(), "max_date", 0); + bool only_chan = to_bool(query->arg("only_in_channels")); - send_request(make_object(nullptr, query_.str(), offset.str(), 100, std::move(filter), min_date, max_date), + send_request(make_object(nullptr, only_chan, query_.str(), offset.str(), 100, std::move(filter), min_date, max_date), td::make_unique(this, std::move(query))); return td::Status::OK(); } @@ -12682,6 +13291,7 @@ void Client::do_send_message(object_ptr input_messa bool force) { auto chat_id = query->arg("chat_id"); auto message_thread_id = get_message_id(query.get(), "message_thread_id"); + auto business_connection_id = query->arg("business_connection_id"); auto r_reply_parameters = get_reply_parameters(query.get()); if (r_reply_parameters.is_error()) { return fail_query_with_error(std::move(query), 400, r_reply_parameters.error().message()); @@ -12706,10 +13316,31 @@ void Client::do_send_message(object_ptr input_messa resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, chat_id = chat_id.str(), message_thread_id, reply_parameters = std::move(reply_parameters), + [this, chat_id_str = chat_id.str(), message_thread_id, business_connection_id = business_connection_id.str(), send_at = std::move(send_at), - disable_notification, protect_content, input_message_content = std::move(input_message_content)]( - object_ptr reply_markup, PromisedQueryPtr query) mutable { + reply_parameters = std::move(reply_parameters), disable_notification, protect_content, + input_message_content = std::move(input_message_content)](object_ptr reply_markup, + PromisedQueryPtr query) mutable { + if (!business_connection_id.empty()) { + auto r_chat_id = get_business_connection_chat_id(chat_id_str); + if (r_chat_id.is_error()) { + return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); + } + auto chat_id = r_chat_id.move_as_ok(); + return check_business_connection( + business_connection_id, std::move(query), + [this, chat_id, reply_parameters = std::move(reply_parameters), disable_notification, protect_content, + reply_markup = std::move(reply_markup), input_message_content = std::move(input_message_content)]( + const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { + send_request( + make_object(business_connection->id_, chat_id, + get_input_message_reply_to(std::move(reply_parameters)), + disable_notification, protect_content, + std::move(reply_markup), std::move(input_message_content)), + td::make_unique(this, business_connection->id_, std::move(query))); + }); + } + auto on_success = [this, disable_notification, protect_content, input_message_content = std::move(input_message_content), send_at = std::move(send_at), @@ -12728,7 +13359,7 @@ void Client::do_send_message(object_ptr input_messa std::move(reply_markup), std::move(input_message_content)), td::make_unique(this, chat_id, std::move(query))); }; - check_reply_parameters(chat_id, std::move(reply_parameters), message_thread_id, std::move(query), + check_reply_parameters(chat_id_str, std::move(reply_parameters), message_thread_id, std::move(query), std::move(on_success)); }); } @@ -12998,6 +13629,7 @@ void Client::add_user(UserInfo *user_info, object_ptr &&user) { user_info->can_join_groups = bot->can_join_groups_; user_info->can_read_all_group_messages = bot->can_read_all_group_messages_; user_info->is_inline_bot = bot->is_inline_; + user_info->can_connect_to_business = bot->can_connect_to_business_; break; } case td_api::userTypeDeleted::ID: @@ -13097,6 +13729,25 @@ const Client::ChatInfo *Client::get_chat(int64 chat_id) const { return chats_.get_pointer(chat_id); } +void Client::set_chat_available_reactions(ChatInfo *chat_info, + object_ptr &&available_reactions) { + CHECK(chat_info != nullptr); + CHECK(available_reactions != nullptr); + switch (available_reactions->get_id()) { + case td_api::chatAvailableReactionsSome::ID: + chat_info->available_reactions = move_object_as(available_reactions); + chat_info->max_reaction_count = chat_info->available_reactions->max_reaction_count_; + break; + case td_api::chatAvailableReactionsAll::ID: + chat_info->available_reactions = nullptr; + chat_info->max_reaction_count = + static_cast(available_reactions.get())->max_reaction_count_; + break; + default: + UNREACHABLE(); + } +} + Client::ChatType Client::get_chat_type(int64 chat_id) const { auto chat_info = get_chat(chat_id); if (chat_info == nullptr) { @@ -13162,6 +13813,28 @@ td::string Client::get_chat_description(int64 chat_id) const { } } +const Client::BusinessConnection *Client::add_business_connection( + object_ptr &&business_connection, bool from_update) { + CHECK(business_connection != nullptr); + auto &connection = business_connections_[business_connection->id_]; + if (connection == nullptr) { + connection = td::make_unique(); + } else if (!from_update) { + return connection.get(); + } + connection->id_ = std::move(business_connection->id_); + connection->user_id_ = business_connection->user_id_; + connection->user_chat_id_ = business_connection->user_chat_id_; + connection->date_ = business_connection->date_; + connection->can_reply_ = business_connection->can_reply_; + connection->is_enabled_ = business_connection->is_enabled_; + return connection.get(); +} + +const Client::BusinessConnection *Client::get_business_connection(const td::string &connection_id) const { + return business_connections_.get_pointer(connection_id); +} + void Client::json_store_file(td::JsonObjectScope &object, const td_api::file *file, bool with_path) const { if (file->id_ == 0) { return; @@ -13337,6 +14010,14 @@ td::Slice Client::get_update_type_name(UpdateType update_type) { return td::Slice("message_reaction"); case UpdateType::MessageReactionCount: return td::Slice("message_reaction_count"); + case UpdateType::BusinessConnection: + return td::Slice("business_connection"); + case UpdateType::BusinessMessage: + return td::Slice("business_message"); + case UpdateType::EditedBusinessMessage: + return td::Slice("edited_business_message"); + case UpdateType::BusinessMessagesDeleted: + return td::Slice("deleted_business_messages"); default: UNREACHABLE(); return td::Slice(); @@ -13552,8 +14233,9 @@ void Client::process_new_callback_query_queue(int64 user_id, int state) { auto message_sticker_set_id = message_info == nullptr ? 0 : get_sticker_set_id(message_info->content); if (!have_sticker_set_name(message_sticker_set_id)) { queue.has_active_request_ = true; - return send_request(make_object(message_sticker_set_id), - td::make_unique(this, message_sticker_set_id, user_id, 0)); + return send_request( + make_object(message_sticker_set_id), + td::make_unique(this, message_sticker_set_id, user_id, 0, td::string())); } auto reply_to_message_id = get_same_chat_reply_to_message_id(message_info); if (reply_to_message_id > 0) { @@ -13562,8 +14244,9 @@ void Client::process_new_callback_query_queue(int64 user_id, int state) { reply_to_message_info == nullptr ? 0 : get_sticker_set_id(reply_to_message_info->content); if (!have_sticker_set_name(reply_sticker_set_id)) { queue.has_active_request_ = true; - return send_request(make_object(reply_sticker_set_id), - td::make_unique(this, reply_sticker_set_id, user_id, 0)); + return send_request( + make_object(reply_sticker_set_id), + td::make_unique(this, reply_sticker_set_id, user_id, 0, td::string())); } } } @@ -13687,6 +14370,34 @@ void Client::add_update_message_reaction_count(object_ptr &&update) { + CHECK(update != nullptr); + const auto *connection = add_business_connection(std::move(update->connection_), true); + auto webhook_queue_id = connection->user_id_ + (static_cast(10) << 33); + add_update(UpdateType::BusinessConnection, JsonBusinessConnection(connection, this), 86400, webhook_queue_id); +} + +void Client::add_update_business_messages_deleted(object_ptr &&update) { + CHECK(update != nullptr); + auto webhook_queue_id = update->chat_id_ + (static_cast(11) << 33); + add_update(UpdateType::BusinessMessagesDeleted, JsonBusinessMessagesDeleted(update.get(), this), 86400, + webhook_queue_id); +} + +void Client::add_new_business_message(object_ptr &&update) { + CHECK(update != nullptr); + CHECK(!update->connection_id_.empty()); + new_business_message_queues_[update->connection_id_].queue_.emplace(std::move(update->message_), false); + process_new_business_message_queue(update->connection_id_); +} + +void Client::add_business_message_edited(object_ptr &&update) { + CHECK(update != nullptr); + CHECK(!update->connection_id_.empty()); + new_business_message_queues_[update->connection_id_].queue_.emplace(std::move(update->message_), true); + process_new_business_message_queue(update->connection_id_); +} + td::int64 Client::choose_added_member_id(const td_api::messageChatAddMembers *message_add_members) const { CHECK(message_add_members != nullptr); for (auto &member_user_id : message_add_members->member_user_ids_) { @@ -13701,9 +14412,17 @@ td::int64 Client::choose_added_member_id(const td_api::messageChatAddMembers *me } bool Client::need_skip_update_message(int64 chat_id, const object_ptr &message, bool is_edited) const { - auto chat = get_chat(chat_id); - CHECK(chat != nullptr); - if (message->is_outgoing_) { + const ChatInfo *chat; + ChatInfo::Type chat_type; + if (chat_id != 0) { + chat = get_chat(chat_id); + CHECK(chat != nullptr); + chat_type = chat->type; + } else { + chat = nullptr; + chat_type = ChatInfo::Type::Private; + } + if (message->is_outgoing_ && chat_id != 0) { switch (message->content_->get_id()) { case td_api::messageChatChangeTitle::ID: case td_api::messageChatChangePhoto::ID: @@ -13739,7 +14458,8 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptrtype == ChatInfo::Type::Supergroup) { + if (chat_type == ChatInfo::Type::Supergroup) { + CHECK(chat != nullptr); auto supergroup_info = get_supergroup_info(chat->supergroup_id); if (supergroup_info->status->get_id() == td_api::chatMemberStatusLeft::ID || supergroup_info->status->get_id() == td_api::chatMemberStatusBanned::ID) { @@ -13780,7 +14500,7 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptrtype != ChatInfo::Type::Supergroup) { + if (chat_type != ChatInfo::Type::Supergroup) { LOG(ERROR) << "Receive messageSupergroupChatCreate in the non-supergroup chat " << chat_id; return true; } @@ -13829,15 +14549,13 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptrid_, true); if (old_message != nullptr && !old_message->is_content_changed) { return true; @@ -13910,6 +14628,7 @@ td::int64 Client::get_same_chat_reply_to_message_id(const MessageInfo *message_i } void Client::drop_internal_reply_to_message_in_another_chat(object_ptr &message) { + CHECK(message != nullptr); if (message->reply_to_ != nullptr && message->reply_to_->get_id() == td_api::messageReplyToMessage::ID) { auto *reply_to = static_cast(message->reply_to_.get()); auto reply_in_chat_id = reply_to->chat_id_; @@ -14099,8 +14818,9 @@ void Client::process_new_message_queue(int64 chat_id, int state) { auto message_sticker_set_id = get_sticker_set_id(message_ref->content_); if (!have_sticker_set_name(message_sticker_set_id)) { queue.has_active_request_ = true; - return send_request(make_object(message_sticker_set_id), - td::make_unique(this, message_sticker_set_id, 0, chat_id)); + return send_request( + make_object(message_sticker_set_id), + td::make_unique(this, message_sticker_set_id, 0, chat_id, td::string())); } if (reply_to_message_id > 0) { auto reply_to_message_info = get_message(chat_id, reply_to_message_id, true); @@ -14108,8 +14828,9 @@ void Client::process_new_message_queue(int64 chat_id, int state) { auto reply_sticker_set_id = get_sticker_set_id(reply_to_message_info->content); if (!have_sticker_set_name(reply_sticker_set_id)) { queue.has_active_request_ = true; - return send_request(make_object(reply_sticker_set_id), - td::make_unique(this, reply_sticker_set_id, 0, chat_id)); + return send_request( + make_object(reply_sticker_set_id), + td::make_unique(this, reply_sticker_set_id, 0, chat_id, td::string())); } } } @@ -14180,6 +14901,57 @@ void Client::process_new_message_queue(int64 chat_id, int state) { new_message_queues_.erase(chat_id); } +void Client::process_new_business_message_queue(const td::string &connection_id) { + auto &queue = new_business_message_queues_[connection_id]; + if (queue.has_active_request_) { + return; + } + if (logging_out_ || closing_) { + new_business_message_queues_.erase(connection_id); + return; + } + while (!queue.queue_.empty()) { + auto &message_ref = queue.queue_.front().message_; + + drop_internal_reply_to_message_in_another_chat(message_ref->message_); + + auto message_sticker_set_id = get_sticker_set_id(message_ref->message_->content_); + if (!have_sticker_set_name(message_sticker_set_id)) { + queue.has_active_request_ = true; + return send_request( + make_object(message_sticker_set_id), + td::make_unique(this, message_sticker_set_id, 0, 0, connection_id)); + } + if (message_ref->reply_to_message_ != nullptr) { + drop_internal_reply_to_message_in_another_chat(message_ref->reply_to_message_); + auto reply_sticker_set_id = get_sticker_set_id(message_ref->reply_to_message_->content_); + if (!have_sticker_set_name(reply_sticker_set_id)) { + queue.has_active_request_ = true; + return send_request( + make_object(reply_sticker_set_id), + td::make_unique(this, reply_sticker_set_id, 0, 0, connection_id)); + } + } + + auto message = std::move(message_ref); + auto is_edited = queue.queue_.front().is_edited_; + queue.queue_.pop(); + if (need_skip_update_message(0, message->message_, is_edited)) { + continue; + } + + auto message_date = message->message_->edit_date_ == 0 ? message->message_->date_ : message->message_->edit_date_; + auto now = get_unix_time(); + auto left_time = message_date + 86400 - now; + auto webhook_queue_id = message->message_->chat_id_ + (static_cast(11) << 33); + auto update_type = is_edited ? UpdateType::EditedBusinessMessage : UpdateType::BusinessMessage; + auto message_info = create_business_message(connection_id, std::move(message)); + add_update(update_type, JsonMessage(message_info.get(), true, get_update_type_name(update_type).str(), this), + left_time, webhook_queue_id); + } + new_business_message_queues_.erase(connection_id); +} + td::unique_ptr Client::delete_message(int64 chat_id, int64 message_id, bool only_from_cache) { auto message_info = std::move(messages_[{chat_id, message_id}]); if (message_info == nullptr) { @@ -14225,7 +14997,14 @@ Client::FullMessageId Client::add_message(object_ptr &&message, message_info = td::make_unique(); } - message_info->id = message_id; + init_message(message_info.get(), std::move(message), force_update_content); + + return {chat_id, message_id}; +} + +void Client::init_message(MessageInfo *message_info, object_ptr &&message, bool force_update_content) { + int64 chat_id = message->chat_id_; + message_info->id = message->id_; message_info->chat_id = chat_id; message_info->message_thread_id = message->message_thread_id_; message_info->date = message->date_; @@ -14289,6 +15068,7 @@ Client::FullMessageId Client::add_message(object_ptr &&message, } message_info->can_be_saved = message->can_be_saved_; + message_info->is_from_offline = message->is_from_offline_; message_info->is_topic_message = message->is_topic_message_; message_info->author_signature = std::move(message->author_signature_); message_info->sender_boost_count = message->sender_boost_count_; @@ -14313,16 +15093,31 @@ Client::FullMessageId Client::add_message(object_ptr &&message, auto sticker_set_id = get_sticker_set_id(message_info->content); if (!have_sticker_set_name(sticker_set_id)) { send_request(make_object(sticker_set_id), - td::make_unique(this, sticker_set_id, 0, 0)); + td::make_unique(this, sticker_set_id, 0, 0, td::string())); } } else if (message->content_->get_id() == td_api::messagePoll::ID) { message_info->content = std::move(message->content_); } - set_message_reply_markup(message_info.get(), std::move(message->reply_markup_)); + set_message_reply_markup(message_info, std::move(message->reply_markup_)); message = nullptr; +} - return {chat_id, message_id}; +td::unique_ptr Client::create_business_message(td::string business_connection_id, + object_ptr &&message) { + auto message_info = td::make_unique(); + CHECK(message != nullptr); + message_info->sender_business_bot_user_id = message->message_->sender_business_bot_user_id_; + init_message(message_info.get(), std::move(message->message_), true); + message_info->business_connection_id = std::move(business_connection_id); + if (message->reply_to_message_ != nullptr) { + message_info->business_reply_to_message = td::make_unique(); + message_info->business_reply_to_message->sender_business_bot_user_id = + message->reply_to_message_->sender_business_bot_user_id_; + init_message(message_info->business_reply_to_message.get(), std::move(message->reply_to_message_), true); + message_info->business_reply_to_message->business_connection_id = message_info->business_connection_id; + } + return message_info; } void Client::update_message_content(int64 chat_id, int64 message_id, object_ptr &&content) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index ecc3db7..6a531cd 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -106,6 +106,11 @@ class Client final : public WebhookActor::Callback { class JsonUsers; class JsonReactionType; class JsonReactionCount; + class JsonBirthdate; + class JsonBusinessStartPage; + class JsonBusinessLocation; + class JsonBusinessOpeningHoursInterval; + class JsonBusinessOpeningHours; class JsonChatPermissions; class JsonChatPhotoInfo; class JsonChatLocation; @@ -176,9 +181,14 @@ class Client final : public WebhookActor::Callback { class JsonGameHighScore; class JsonMessageReactionUpdated; class JsonMessageReactionCountUpdated; + class JsonBusinessConnection; + class JsonBusinessMessagesDeleted; class JsonAddress; class JsonOrderInfo; class JsonStory; + class JsonBackgroundFill; + class JsonBackgroundType; + class JsonChatBackground; class JsonSuccessfulPaymentBot; class JsonEncryptedPassportElement; class JsonEncryptedCredentials; @@ -191,6 +201,7 @@ class Client final : public WebhookActor::Callback { class JsonChatSetMessageAutoDeleteTime; class JsonWriteAccessAllowed; class JsonUserShared; + class JsonSharedUser; class JsonUsersShared; class JsonChatShared; class JsonGiveaway; @@ -220,7 +231,9 @@ class Client final : public WebhookActor::Callback { class TdOnInitCallback; class TdOnGetUserProfilePhotosCallback; class TdOnSendMessageCallback; + class TdOnSendBusinessMessageCallback; class TdOnSendMessageAlbumCallback; + class TdOnSendBusinessMessageAlbumCallback; class TdOnForwardMessagesCallback; class TdOnDeleteFailedToSendMessageCallback; class TdOnEditMessageCallback; @@ -241,6 +254,7 @@ class Client final : public WebhookActor::Callback { class TdOnGetChatFullInfoCallback; class TdOnGetChatStickerSetCallback; class TdOnGetChatCustomEmojiStickerSetCallback; + class TdOnGetChatBusinessStartPageStickerSetCallback; class TdOnGetChatPinnedMessageCallback; class TdOnGetChatPinnedMessageToUnpinCallback; class TdOnGetGroupMembersCallback; @@ -281,6 +295,7 @@ class Client final : public WebhookActor::Callback { void on_get_callback_query_message(object_ptr message, int64 user_id, int state); void on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, int64 new_message_chat_id, + const td::string &new_message_business_connection_id, object_ptr sticker_set); void on_get_sticker_set_name(int64 set_id, const td::string &name); @@ -337,6 +352,8 @@ class Client final : public WebhookActor::Callback { template class TdOnCheckMessageThreadCallback; template + class TdOnCheckBusinessConnectionCallback; + template class TdOnCheckRemoteFileIdCallback; template class TdOnGetChatMemberCallback; @@ -365,6 +382,12 @@ class Client final : public WebhookActor::Callback { template void check_chat_no_fail(td::Slice chat_id_str, PromisedQueryPtr query, OnSuccess on_success); + static td::Result get_business_connection_chat_id(td::Slice chat_id_str); + + template + void check_business_connection(const td::string &business_connection_id, PromisedQueryPtr query, + OnSuccess on_success); + template void check_bot_command_scope(BotCommandScope &&scope, PromisedQueryPtr query, OnSuccess on_success); @@ -419,6 +442,8 @@ class Client final : public WebhookActor::Callback { static object_ptr get_input_message_reply_to(CheckedReplyParameters &&reply_parameters); + static object_ptr get_input_message_reply_to(InputReplyParameters &&reply_parameters); + static td::Result get_reply_parameters(const Query *query); static td::Result get_reply_parameters(td::JsonValue &&value); @@ -517,14 +542,17 @@ class Client final : public WebhookActor::Callback { static td::Result> get_sticker_format(td::Slice sticker_format); + td::Result> get_legacy_input_sticker(const Query *query) const; + td::Result> get_input_sticker(const Query *query) const; - td::Result> get_input_sticker(const Query *query, td::JsonValue &&value) const; + td::Result> get_input_sticker(const Query *query, td::JsonValue &&value, + td::Slice default_sticker_format) const; - td::Result>> get_input_stickers( - const Query *query, object_ptr &sticker_format) const; + td::Result>> get_input_stickers(const Query *query) const; - static td::Result> get_sticker_input_file(const Query *query); + static td::Result> get_sticker_input_file(const Query *query, + td::Slice field_name = "sticker"); static td::Result get_passport_element_hash(td::Slice encoded_hash); @@ -581,7 +609,7 @@ class Client final : public WebhookActor::Callback { bool protect_content, object_ptr &&scheduling_state); - static td::Result> get_poll_options(const Query *query); + static td::Result>> get_poll_options(const Query *query); static td::Result> get_reaction_type(td::JsonValue &&value); @@ -694,6 +722,7 @@ class Client final : public WebhookActor::Callback { td::Status process_create_chat_invite_link_query(PromisedQueryPtr &query); td::Status process_edit_chat_invite_link_query(PromisedQueryPtr &query); td::Status process_revoke_chat_invite_link_query(PromisedQueryPtr &query); + td::Status process_get_business_connection_query(PromisedQueryPtr &query); td::Status process_get_chat_query(PromisedQueryPtr &query); td::Status process_set_chat_photo_query(PromisedQueryPtr &query); td::Status process_delete_chat_photo_query(PromisedQueryPtr &query); @@ -737,6 +766,7 @@ class Client final : public WebhookActor::Callback { td::Status process_upload_sticker_file_query(PromisedQueryPtr &query); td::Status process_create_new_sticker_set_query(PromisedQueryPtr &query); td::Status process_add_sticker_to_set_query(PromisedQueryPtr &query); + td::Status process_replace_sticker_in_set_query(PromisedQueryPtr &query); td::Status process_set_sticker_set_title_query(PromisedQueryPtr &query); td::Status process_set_sticker_set_thumbnail_query(PromisedQueryPtr &query); td::Status process_set_custom_emoji_sticker_set_thumbnail_query(PromisedQueryPtr &query); @@ -878,6 +908,9 @@ class Client final : public WebhookActor::Callback { object_ptr photo; td::string bio; + object_ptr birthdate; + object_ptr business_info; + int64 personal_chat_id = 0; // start custom properties bool is_verified = false; @@ -888,6 +921,7 @@ class Client final : public WebhookActor::Callback { bool have_access = false; bool can_join_groups = false; bool can_read_all_group_messages = false; + bool can_connect_to_business = false; bool is_inline_bot = false; bool has_private_forwards = false; bool has_restricted_voice_and_video_messages = false; @@ -959,6 +993,7 @@ class Client final : public WebhookActor::Callback { int64 background_custom_emoji_id = 0; int64 profile_background_custom_emoji_id = 0; bool has_protected_content = false; + int32 max_reaction_count = 0; object_ptr available_reactions; object_ptr photo_info; object_ptr permissions; @@ -971,6 +1006,9 @@ class Client final : public WebhookActor::Callback { ChatInfo *add_chat(int64 chat_id); const ChatInfo *get_chat(int64 chat_id) const; + void set_chat_available_reactions(ChatInfo *chat_info, + object_ptr &&available_reactions); + enum class ChatType { Private, Group, Supergroup, Channel, Unknown }; ChatType get_chat_type(int64 chat_id) const; @@ -989,12 +1027,15 @@ class Client final : public WebhookActor::Callback { int32 sender_boost_count = 0; object_ptr forward_origin; td::string author_signature; + td::unique_ptr business_reply_to_message; object_ptr reply_to_message; object_ptr reply_to_story; int64 media_album_id = 0; int64 via_bot_user_id = 0; object_ptr content; object_ptr reply_markup; + td::string business_connection_id; + int64 sender_business_bot_user_id = 0; // start custom properties int32 views = 0; @@ -1007,9 +1048,22 @@ class Client final : public WebhookActor::Callback { bool can_be_saved = false; bool is_automatic_forward = false; bool is_topic_message = false; + bool is_from_offline = false; mutable bool is_content_changed = false; }; + struct BusinessConnection { + td::string id_; + int64 user_id_ = 0; + int64 user_chat_id_ = 0; + int32 date_ = 0; + bool can_reply_ = false; + bool is_enabled_ = false; + }; + const BusinessConnection *add_business_connection(object_ptr &&business_connection, + bool from_update); + const BusinessConnection *get_business_connection(const td::string &connection_id) const; + static int64 get_same_chat_reply_to_message_id(const td_api::messageReplyToMessage *reply_to, int64 message_thread_id); @@ -1034,7 +1088,7 @@ class Client final : public WebhookActor::Callback { static bool are_equal_inline_keyboards(const td_api::replyMarkupInlineKeyboard *lhs, const td_api::replyMarkupInlineKeyboard *rhs); - void set_message_reply_markup(MessageInfo *message_info, object_ptr &&reply_markup); + static void set_message_reply_markup(MessageInfo *message_info, object_ptr &&reply_markup); static int64 get_sticker_set_id(const object_ptr &content); @@ -1068,6 +1122,12 @@ class Client final : public WebhookActor::Callback { void process_new_message_queue(int64 chat_id, int state); + void add_new_business_message(object_ptr &&update); + + void add_business_message_edited(object_ptr &&update); + + void process_new_business_message_queue(const td::string &connection_id); + struct FullMessageId { int64 chat_id; int64 message_id; @@ -1089,9 +1149,13 @@ class Client final : public WebhookActor::Callback { }; FullMessageId add_message(object_ptr &&message, bool force_update_content = false); + void init_message(MessageInfo *message_info, object_ptr &&message, bool force_update_content); const MessageInfo *get_message(int64 chat_id, int64 message_id, bool force_cache) const; MessageInfo *get_message_editable(int64 chat_id, int64 message_id); + td::unique_ptr create_business_message(td::string business_connection_id, + object_ptr &&message); + void update_message_content(int64 chat_id, int64 message_id, object_ptr &&content); void on_update_message_edited(int64 chat_id, int64 message_id, int32 edit_date, @@ -1146,6 +1210,10 @@ class Client final : public WebhookActor::Callback { void add_update_message_reaction_count(object_ptr &&update); + void add_update_business_connection(object_ptr &&update); + + void add_update_business_messages_deleted(object_ptr &&update); + // append only before Size enum class UpdateType : int32 { Message, @@ -1168,6 +1236,10 @@ class Client final : public WebhookActor::Callback { ChatBoostRemoved, MessageReaction, MessageReactionCount, + BusinessConnection, + BusinessMessage, + EditedBusinessMessage, + BusinessMessagesDeleted, Size }; @@ -1239,6 +1311,7 @@ class Client final : public WebhookActor::Callback { td::WaitFreeHashMap> groups_; td::WaitFreeHashMap> supergroups_; td::WaitFreeHashMap> chats_; + td::WaitFreeHashMap> business_connections_; td::FlatHashMap> file_download_listeners_; td::FlatHashSet download_started_file_ids_; @@ -1276,6 +1349,20 @@ class Client final : public WebhookActor::Callback { }; td::FlatHashMap new_message_queues_; // chat_id -> queue + struct NewBusinessMessage { + object_ptr message_; + bool is_edited_ = false; + + NewBusinessMessage(object_ptr &&message, bool is_edited) + : message_(std::move(message)), is_edited_(is_edited) { + } + }; + struct NewBusinessMessageQueue { + std::queue queue_; + bool has_active_request_ = false; + }; + td::FlatHashMap new_business_message_queues_; // connection_id -> queue + struct NewCallbackQueryQueue { std::queue> queue_; bool has_active_request_ = false; diff --git a/telegram-bot-api/WebhookActor.cpp b/telegram-bot-api/WebhookActor.cpp index 3a243db..e86845e 100644 --- a/telegram-bot-api/WebhookActor.cpp +++ b/telegram-bot-api/WebhookActor.cpp @@ -590,8 +590,7 @@ void WebhookActor::send_updates() { void WebhookActor::handle(td::unique_ptr response) { SCOPE_EXIT { - bool dummy = false; - td::Scheduler::instance()->destroy_on_scheduler(SharedData::get_file_gc_scheduler_id(), response, dummy); + td::Scheduler::instance()->destroy_on_scheduler_unique_ptr(SharedData::get_file_gc_scheduler_id(), response); }; auto connection_id = get_link_token(); diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index 8a80223..b82f33e 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -165,7 +165,7 @@ int main(int argc, char *argv[]) { auto start_time = td::Time::now(); auto shared_data = std::make_shared(); auto parameters = std::make_unique(); - parameters->version_ = "7.1"; + parameters->version_ = "7.3"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats();