// // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #pragma once #include "td/telegram/secret_api.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" #include "td/actor/MultiPromise.h" #include "td/actor/PromiseFuture.h" #include "td/actor/SignalSlot.h" #include "td/actor/Timeout.h" #include "td/db/binlog/BinlogEvent.h" #include "td/telegram/AccessRights.h" #include "td/telegram/CallDiscardReason.h" #include "td/telegram/ChannelId.h" #include "td/telegram/ChatId.h" #include "td/telegram/Contact.h" #include "td/telegram/DialogId.h" #include "td/telegram/DialogParticipant.h" #include "td/telegram/DocumentsManager.h" #include "td/telegram/files/FileId.h" #include "td/telegram/Game.h" #include "td/telegram/Global.h" #include "td/telegram/Location.h" #include "td/telegram/MessageEntity.h" #include "td/telegram/MessageId.h" #include "td/telegram/MessagesDb.h" #include "td/telegram/net/NetQuery.h" #include "td/telegram/Payments.h" #include "td/telegram/Photo.h" #include "td/telegram/ReplyMarkup.h" #include "td/telegram/SecretChatId.h" #include "td/telegram/SecretInputMedia.h" #include "td/telegram/UserId.h" #include "td/telegram/WebPageId.h" #include "td/utils/buffer.h" #include "td/utils/ChangesProcessor.h" #include "td/utils/common.h" #include "td/utils/Heap.h" #include "td/utils/Hints.h" #include "td/utils/logging.h" #include "td/utils/Status.h" #include "td/utils/StringBuilder.h" #include "td/utils/tl_storers.h" #include #include #include #include #include #include #include #include #include namespace td { class Td; class MultiSequenceDispatcher; // Do not forget to update MessagesManager::update_message_content when one of the inheritors of this class changes class MessageContent { public: virtual int32 get_id() const = 0; virtual ~MessageContent() = default; }; class MessageText : public MessageContent { public: string text; vector entities; WebPageId web_page_id; MessageText() = default; MessageText(string text, vector &&entities, WebPageId web_page_id) : text(std::move(text)), entities(std::move(entities)), web_page_id(web_page_id) { } static const int32 ID = 0; int32 get_id() const override { return ID; } }; class MessageAnimation : public MessageContent { public: FileId file_id; string caption; MessageAnimation() = default; MessageAnimation(FileId file_id, string &&caption) : file_id(file_id), caption(std::move(caption)) { } static const int32 ID = 1; int32 get_id() const override { return ID; } }; class MessageAudio : public MessageContent { public: FileId file_id; string caption; MessageAudio() = default; MessageAudio(FileId file_id, string &&caption) : file_id(file_id), caption(std::move(caption)) { } static const int32 ID = 2; int32 get_id() const override { return ID; } }; class MessageDocument : public MessageContent { public: FileId file_id; string caption; MessageDocument() = default; MessageDocument(FileId file_id, string &&caption) : file_id(file_id), caption(std::move(caption)) { } static const int32 ID = 3; int32 get_id() const override { return ID; } }; class MessagePhoto : public MessageContent { public: Photo photo; string caption; MessagePhoto() = default; MessagePhoto(Photo &&photo, string &&caption) : photo(std::move(photo)), caption(std::move(caption)) { } static const int32 ID = 4; int32 get_id() const override { return ID; } }; class MessageSticker : public MessageContent { public: FileId file_id; MessageSticker() = default; explicit MessageSticker(FileId file_id) : file_id(file_id) { } static const int32 ID = 5; int32 get_id() const override { return ID; } }; class MessageVideo : public MessageContent { public: FileId file_id; string caption; MessageVideo() = default; MessageVideo(FileId file_id, string &&caption) : file_id(file_id), caption(std::move(caption)) { } static const int32 ID = 6; int32 get_id() const override { return ID; } }; class MessageVoiceNote : public MessageContent { public: FileId file_id; string caption; bool is_listened; MessageVoiceNote() = default; MessageVoiceNote(FileId file_id, string &&caption, bool is_listened) : file_id(file_id), caption(std::move(caption)), is_listened(is_listened) { } static const int32 ID = 7; int32 get_id() const override { return ID; } }; class MessageContact : public MessageContent { public: Contact contact; MessageContact() = default; explicit MessageContact(Contact &&contact) : contact(std::move(contact)) { } static const int32 ID = 8; int32 get_id() const override { return ID; } }; class MessageLocation : public MessageContent { public: Location location; MessageLocation() = default; explicit MessageLocation(Location &&location) : location(std::move(location)) { } static const int32 ID = 9; int32 get_id() const override { return ID; } }; class MessageVenue : public MessageContent { public: Venue venue; MessageVenue() = default; explicit MessageVenue(Venue &&venue) : venue(std::move(venue)) { } static const int32 ID = 10; int32 get_id() const override { return ID; } }; class MessageChatCreate : public MessageContent { public: string title; vector participant_user_ids; MessageChatCreate() = default; MessageChatCreate(string &&title, vector &&participant_user_ids) : title(std::move(title)), participant_user_ids(std::move(participant_user_ids)) { } static const int32 ID = 11; int32 get_id() const override { return ID; } }; class MessageChatChangeTitle : public MessageContent { public: string title; MessageChatChangeTitle() = default; explicit MessageChatChangeTitle(string &&title) : title(std::move(title)) { } static const int32 ID = 12; int32 get_id() const override { return ID; } }; class MessageChatChangePhoto : public MessageContent { public: Photo photo; MessageChatChangePhoto() = default; explicit MessageChatChangePhoto(Photo &&photo) : photo(std::move(photo)) { } static const int32 ID = 13; int32 get_id() const override { return ID; } }; class MessageChatDeletePhoto : public MessageContent { public: static const int32 ID = 14; int32 get_id() const override { return ID; } }; class MessageChatDeleteHistory : public MessageContent { public: static const int32 ID = 15; int32 get_id() const override { return ID; } }; class MessageChatAddUsers : public MessageContent { public: vector user_ids; MessageChatAddUsers() = default; explicit MessageChatAddUsers(vector &&user_ids) : user_ids(std::move(user_ids)) { } static const int32 ID = 16; int32 get_id() const override { return ID; } }; class MessageChatJoinedByLink : public MessageContent { public: static const int32 ID = 17; int32 get_id() const override { return ID; } }; class MessageChatDeleteUser : public MessageContent { public: UserId user_id; MessageChatDeleteUser() = default; explicit MessageChatDeleteUser(UserId user_id) : user_id(user_id) { } static const int32 ID = 18; int32 get_id() const override { return ID; } }; class MessageChatMigrateTo : public MessageContent { public: ChannelId migrated_to_channel_id; MessageChatMigrateTo() = default; explicit MessageChatMigrateTo(ChannelId migrated_to_channel_id) : migrated_to_channel_id(migrated_to_channel_id) { } static const int32 ID = 19; int32 get_id() const override { return ID; } }; class MessageChannelCreate : public MessageContent { public: string title; MessageChannelCreate() = default; explicit MessageChannelCreate(string &&title) : title(std::move(title)) { } static const int32 ID = 20; int32 get_id() const override { return ID; } }; class MessageChannelMigrateFrom : public MessageContent { public: string title; ChatId migrated_from_chat_id; MessageChannelMigrateFrom() = default; MessageChannelMigrateFrom(string &&title, ChatId migrated_from_chat_id) : title(std::move(title)), migrated_from_chat_id(migrated_from_chat_id) { } static const int32 ID = 21; int32 get_id() const override { return ID; } }; class MessagePinMessage : public MessageContent { public: MessageId message_id; MessagePinMessage() = default; explicit MessagePinMessage(MessageId message_id) : message_id(message_id) { } static const int32 ID = 22; int32 get_id() const override { return ID; } }; class MessageGame : public MessageContent { public: Game game; MessageGame() = default; explicit MessageGame(Game &&game) : game(std::move(game)) { } static const int32 ID = 23; int32 get_id() const override { return ID; } }; class MessageGameScore : public MessageContent { public: MessageId game_message_id; int64 game_id; int32 score; MessageGameScore() = default; MessageGameScore(MessageId game_message_id, int64 game_id, int32 score) : game_message_id(game_message_id), game_id(game_id), score(score) { } static const int32 ID = 24; int32 get_id() const override { return ID; } }; class MessageScreenshotTaken : public MessageContent { public: static const int32 ID = 25; int32 get_id() const override { return ID; } }; class MessageChatSetTtl : public MessageContent { public: int32 ttl; MessageChatSetTtl() = default; explicit MessageChatSetTtl(int32 ttl) : ttl(ttl) { } static const int32 ID = 26; int32 get_id() const override { return ID; } }; class MessageUnsupported : public MessageContent { // TODO save a layer in which the message was received to // automatically reget it if the layer changes public: static const int32 ID = 27; int32 get_id() const override { return ID; } }; class MessageCall : public MessageContent { public: int64 call_id; int32 duration; CallDiscardReason discard_reason; MessageCall() = default; MessageCall(int64 call_id, int32 duration, CallDiscardReason discard_reason) : call_id(call_id), duration(duration), discard_reason(discard_reason) { } static const int32 ID = 28; int32 get_id() const override { return ID; } }; class MessageInvoice : public MessageContent { public: string title; string description; Photo photo; string start_parameter; // InputMessageInvoice Invoice invoice; string payload; string provider_token; string provider_data; // MessageInvoice int64 total_amount = 0; MessageId receipt_message_id; MessageInvoice() = default; MessageInvoice(string &&title, string &&description, Photo &&photo, string &&start_parameter, int64 total_amount, string &¤cy, bool is_test, bool need_shipping_address, MessageId receipt_message_id) : title(std::move(title)) , description(std::move(description)) , photo(std::move(photo)) , start_parameter(std::move(start_parameter)) , invoice(std::move(currency), is_test, need_shipping_address) , payload() , provider_token() , provider_data() , total_amount(total_amount) , receipt_message_id(receipt_message_id) { } static const int32 ID = 29; int32 get_id() const override { return ID; } }; class MessagePaymentSuccessful : public MessageContent { public: MessageId invoice_message_id; string currency; int64 total_amount = 0; // bots only part string invoice_payload; string shipping_option_id; unique_ptr order_info; string telegram_payment_charge_id; string provider_payment_charge_id; MessagePaymentSuccessful() = default; MessagePaymentSuccessful(MessageId invoice_message_id, string &¤cy, int64 total_amount) : invoice_message_id(invoice_message_id), currency(std::move(currency)), total_amount(total_amount) { } static const int32 ID = 30; int32 get_id() const override { return ID; } }; class MessageVideoNote : public MessageContent { public: FileId file_id; bool is_viewed = false; MessageVideoNote() = default; MessageVideoNote(FileId file_id, bool is_viewed) : file_id(file_id), is_viewed(is_viewed) { } static const int32 ID = 31; int32 get_id() const override { return ID; } }; class MessageContactRegistered : public MessageContent { public: static const int32 ID = 32; int32 get_id() const override { return ID; } }; class MessageExpiredPhoto : public MessageContent { public: MessageExpiredPhoto() = default; static const int32 ID = 33; int32 get_id() const override { return ID; } }; class MessageExpiredVideo : public MessageContent { public: MessageExpiredVideo() = default; static const int32 ID = 34; int32 get_id() const override { return ID; } }; class MessageLiveLocation : public MessageContent { public: Location location; int32 period; MessageLiveLocation() = default; MessageLiveLocation(Location &&location, int32 period) : location(std::move(location)), period(period) { } static const int32 ID = 35; int32 get_id() const override { return ID; } }; class MessageCustomServiceAction : public MessageContent { public: string message; MessageCustomServiceAction() = default; explicit MessageCustomServiceAction(string &&message) : message(std::move(message)) { } static const int32 ID = 36; int32 get_id() const override { return ID; } }; class InputMessageText { public: string text; bool disable_web_page_preview = false; bool clear_draft = false; vector entities; InputMessageText() = default; InputMessageText(string text, bool disable_web_page_preview, bool clear_draft, vector entities) : text(std::move(text)) , disable_web_page_preview(disable_web_page_preview) , clear_draft(clear_draft) , entities(std::move(entities)) { } }; bool operator==(const InputMessageText &lhs, const InputMessageText &rhs); bool operator!=(const InputMessageText &lhs, const InputMessageText &rhs); class DraftMessage { public: int32 date; MessageId reply_to_message_id; InputMessageText input_message_text; }; using NotificationSettingsScope = int64; constexpr NotificationSettingsScope NOTIFICATION_SETTINGS_FOR_PRIVATE_CHATS = std::numeric_limits::min(); constexpr NotificationSettingsScope NOTIFICATION_SETTINGS_FOR_GROUP_CHATS = std::numeric_limits::min() + 1; constexpr NotificationSettingsScope NOTIFICATION_SETTINGS_FOR_ALL_CHATS = std::numeric_limits::min() + 2; class NotificationSettings { public: int32 mute_until = 0; string sound = "default"; bool show_preview = true; bool silent_send_message = false; bool is_synchronized = false; NotificationSettings() = default; NotificationSettings(int32 mute_until, string sound, bool show_preview, bool silent_send_message) : mute_until(mute_until) , sound(std::move(sound)) , show_preview(show_preview) , silent_send_message(silent_send_message) , is_synchronized(true) { } }; inline constexpr size_t search_messages_filter_size() { return static_cast(SearchMessagesFilter::Size) - 1; } inline int32 search_messages_filter_index(SearchMessagesFilter filter) { CHECK(filter != SearchMessagesFilter::Empty); return static_cast(filter) - 1; } inline int32 search_messages_filter_index_mask(SearchMessagesFilter filter) { if (filter == SearchMessagesFilter::Empty) { return 0; } return 1 << search_messages_filter_index(filter); } inline int32 search_calls_filter_index(SearchMessagesFilter filter) { CHECK(filter == SearchMessagesFilter::Call || filter == SearchMessagesFilter::MissedCall); return static_cast(filter) - static_cast(SearchMessagesFilter::Call); } class DialogDate { int64 order; DialogId dialog_id; public: DialogDate(int64 order, DialogId dialog_id) : order(order), dialog_id(dialog_id) { } bool operator<(const DialogDate &other) const { return order > other.order || (order == other.order && dialog_id.get() > other.dialog_id.get()); } bool operator<=(const DialogDate &other) const { return order >= other.order && (order != other.order || dialog_id.get() >= other.dialog_id.get()); } bool operator==(const DialogDate &other) const { return order == other.order && dialog_id == other.dialog_id; } bool operator!=(const DialogDate &other) const { return order != other.order || dialog_id != other.dialog_id; } int64 get_order() const { return order; } DialogId get_dialog_id() const { return dialog_id; } int32 get_date() const { return static_cast((order >> 32) & 0x7FFFFFFF); } MessageId get_message_id() const { return MessageId(ServerMessageId(static_cast(order & 0x7FFFFFFF))); } friend struct DialogDateHash; friend StringBuilder &operator<<(StringBuilder &string_builder, DialogDate dialog_date); }; const DialogDate MIN_DIALOG_DATE(std::numeric_limits::max(), DialogId()); const DialogDate MAX_DIALOG_DATE(0, DialogId()); const int64 DEFAULT_ORDER = -1; struct DialogDateHash { std::size_t operator()(const DialogDate &dialog_date) const { return std::hash()(dialog_date.order) * 2023654985u + DialogIdHash()(dialog_date.dialog_id); } }; inline StringBuilder &operator<<(StringBuilder &string_builder, DialogDate dialog_date) { return string_builder << "[" << dialog_date.order << ", " << dialog_date.dialog_id.get() << "]"; } class dummyUpdate : public telegram_api::Update { public: static constexpr int32 ID = 1234567891; int32 get_id() const override { return ID; } void store(TlStorerUnsafe &s) const override { UNREACHABLE(); } void store(TlStorerCalcLength &s) const override { UNREACHABLE(); } void store(TlStorerToString &s, const char *field_name) const override; }; class Dependencies { public: std::unordered_set user_ids; std::unordered_set chat_ids; std::unordered_set channel_ids; std::unordered_set secret_chat_ids; std::unordered_set dialog_ids; std::unordered_set web_page_ids; }; struct CallsDbState { std::array first_calls_database_message_id_by_index; std::array message_count_by_index; }; class MessagesManager : public Actor { public: // static constexpr int32 MESSAGE_FLAG_IS_UNREAD = 1 << 0; static constexpr int32 MESSAGE_FLAG_IS_OUT = 1 << 1; static constexpr int32 MESSAGE_FLAG_IS_FORWARDED = 1 << 2; static constexpr int32 MESSAGE_FLAG_IS_REPLY = 1 << 3; static constexpr int32 MESSAGE_FLAG_HAS_MENTION = 1 << 4; static constexpr int32 MESSAGE_FLAG_HAS_UNREAD_CONTENT = 1 << 5; static constexpr int32 MESSAGE_FLAG_HAS_REPLY_MARKUP = 1 << 6; static constexpr int32 MESSAGE_FLAG_HAS_ENTITIES = 1 << 7; static constexpr int32 MESSAGE_FLAG_HAS_FROM_ID = 1 << 8; static constexpr int32 MESSAGE_FLAG_HAS_MEDIA = 1 << 9; static constexpr int32 MESSAGE_FLAG_HAS_VIEWS = 1 << 10; static constexpr int32 MESSAGE_FLAG_IS_SENT_VIA_BOT = 1 << 11; static constexpr int32 MESSAGE_FLAG_IS_SILENT = 1 << 13; static constexpr int32 MESSAGE_FLAG_IS_POST = 1 << 14; static constexpr int32 MESSAGE_FLAG_HAS_EDIT_DATE = 1 << 15; static constexpr int32 MESSAGE_FLAG_HAS_AUTHOR_SIGNATURE = 1 << 16; static constexpr int32 MESSAGE_FLAG_HAS_MEDIA_ALBUM_ID = 1 << 17; static constexpr int32 MESSAGE_FORWARD_HEADER_FLAG_HAS_AUTHOR_ID = 1 << 0; static constexpr int32 MESSAGE_FORWARD_HEADER_FLAG_HAS_CHANNEL_ID = 1 << 1; static constexpr int32 MESSAGE_FORWARD_HEADER_FLAG_HAS_MESSAGE_ID = 1 << 2; static constexpr int32 MESSAGE_FORWARD_HEADER_FLAG_HAS_AUTHOR_SIGNATURE = 1 << 3; static constexpr int32 MESSAGE_FORWARD_HEADER_FLAG_HAS_SAVED_FROM = 1 << 4; static constexpr int32 SEND_MESSAGE_FLAG_IS_REPLY = 1 << 0; static constexpr int32 SEND_MESSAGE_FLAG_DISABLE_WEB_PAGE_PREVIEW = 1 << 1; static constexpr int32 SEND_MESSAGE_FLAG_HAS_REPLY_MARKUP = 1 << 2; static constexpr int32 SEND_MESSAGE_FLAG_HAS_ENTITIES = 1 << 3; // static constexpr int32 SEND_MESSAGE_FLAG_IS_POST = 1 << 4; static constexpr int32 SEND_MESSAGE_FLAG_DISABLE_NOTIFICATION = 1 << 5; static constexpr int32 SEND_MESSAGE_FLAG_FROM_BACKGROUND = 1 << 6; static constexpr int32 SEND_MESSAGE_FLAG_CLEAR_DRAFT = 1 << 7; static constexpr int32 SEND_MESSAGE_FLAG_WITH_MY_SCORE = 1 << 8; static constexpr int32 SEND_MESSAGE_FLAG_GROUP_MEDIA = 1 << 9; static constexpr int32 SEND_MESSAGE_FLAG_HAS_MESSAGE = 1 << 11; MessagesManager(Td *td, ActorShared<> parent); MessagesManager(const MessagesManager &) = delete; MessagesManager &operator=(const MessagesManager &) = delete; MessagesManager(MessagesManager &&) = delete; MessagesManager &operator=(MessagesManager &&) = delete; ~MessagesManager() override; static vector get_message_ids(const vector &input_message_ids); static vector get_message_ids(const vector &input_message_ids); static vector get_server_message_ids(const vector &message_ids); static MessageId get_message_id(const tl_object_ptr &message_ptr); DialogId get_message_dialog_id(const tl_object_ptr &message_ptr) const; FullMessageId get_full_message_id(const tl_object_ptr &message_ptr) const; static int32 get_message_date(const tl_object_ptr &message_ptr); tl_object_ptr get_input_peer(DialogId dialog_id, AccessRights access_rights) const; vector> get_input_peers(const vector &dialog_ids, AccessRights access_rights) const; tl_object_ptr get_input_encrypted_chat(DialogId dialog_id, AccessRights access_rights) const; bool have_input_peer(DialogId dialog_id, AccessRights access_rights) const; void on_get_messages(vector> &&messages, bool is_channel_message, const char *source); void on_get_history(DialogId dialog_id, MessageId from_message_id, int32 offset, int32 limit, bool from_the_end, vector> &&messages); void on_get_public_dialogs_search_result(const string &query, vector> &&peers); void on_failed_public_dialogs_search(const string &query, Status &&error); void on_get_dialog_messages_search_result(DialogId dialog_id, const string &query, UserId sender_user_id, MessageId from_message_id, int32 offset, int32 limit, SearchMessagesFilter filter, int64 random_id, int32 total_count, vector> &&messages); void on_failed_dialog_messages_search(int64 random_id); void on_get_messages_search_result(const string &query, int32 offset_date, DialogId offset_dialog_id, MessageId offset_message_id, int32 limit, int64 random_id, int32 total_count, vector> &&messages); void on_failed_messages_search(int64 random_id); void on_get_recent_locations(DialogId dialog_id, int32 limit, int64 random_id, int32 total_count, vector> &&messages); void on_get_recent_locations_failed(int64 random_id); // if message is from_update, flags have_previous and have_next are ignored and should be both true FullMessageId on_get_message(tl_object_ptr message_ptr, bool from_update, bool is_channel_message, bool have_previous, bool have_next, const char *source); void open_secret_message(SecretChatId secret_chat_id, int64 random_id, Promise<>); void on_send_secret_message_success(int64 random_id, MessageId message_id, int32 date, tl_object_ptr file_ptr, Promise<> promise); void on_send_secret_message_error(int64 random_id, Status error, Promise<> promise); void delete_secret_messages(SecretChatId secret_chat_id, std::vector random_ids, Promise<> promise); void delete_secret_chat_history(SecretChatId secret_chat_id, MessageId last_message_id, Promise<> promise); void read_secret_chat_outbox(SecretChatId secret_chat_id, int32 up_to_date, int32 read_date); void on_get_secret_message(SecretChatId secret_chat_id, UserId user_id, MessageId message_id, int32 date, tl_object_ptr file, tl_object_ptr message, Promise<> promise); void on_secret_chat_screenshot_taken(SecretChatId secret_chat_id, UserId user_id, MessageId message_id, int32 date, int64 random_id, Promise<> promise); void on_secret_chat_ttl_changed(SecretChatId secret_chat_id, UserId user_id, MessageId message_id, int32 date, int32 ttl, int64 random_id, Promise<> promise); void on_update_sent_text_message(int64 random_id, tl_object_ptr message_media, vector> &&entities); void on_update_message_web_page(FullMessageId full_message_id, bool have_web_page); void on_get_dialogs(vector> &&dialogs, int32 total_count, vector> &&messages, Promise &&promise); void on_get_common_dialogs(UserId user_id, vector> &&chats, int32 total_count); bool on_update_message_id(int64 random_id, MessageId new_message_id, const string &source); void on_update_dialog_draft_message(DialogId dialog_id, tl_object_ptr &&draft_message); void on_update_dialog_pinned(DialogId dialog_id, bool is_pinned); void on_update_pinned_dialogs(); void on_update_service_notification(tl_object_ptr &&update); void on_update_contact_registered(tl_object_ptr &&update); void on_update_new_channel_message(tl_object_ptr &&update); void on_update_edit_channel_message(tl_object_ptr &&update); void on_update_read_channel_inbox(tl_object_ptr &&update); void on_update_read_channel_outbox(tl_object_ptr &&update); void on_update_read_channel_messages_contents( tl_object_ptr &&update); void on_update_channel_too_long(tl_object_ptr &&update, bool force_apply); void on_update_message_views(FullMessageId full_message_id, int32 views); void on_read_channel_inbox(ChannelId channel_id, MessageId max_message_id, int32 server_unread_count); void on_read_channel_outbox(ChannelId channel_id, MessageId max_message_id); void on_update_channel_max_unavailable_message_id(ChannelId channel_id, MessageId max_unavailable_message_id); void delete_messages(DialogId dialog_id, const vector &message_ids, bool revoke, Promise &&promise); void delete_dialog_history(DialogId dialog_id, bool remove_from_dialog_list, Promise &&promise); void delete_dialog_messages_from_user(DialogId dialog_id, UserId user_id, Promise &&promise); void delete_dialog(DialogId dialog_id); void read_all_dialog_mentions(DialogId dialog_id, Promise &&promise); Status add_recently_found_dialog(DialogId dialog_id) TD_WARN_UNUSED_RESULT; Status remove_recently_found_dialog(DialogId dialog_id) TD_WARN_UNUSED_RESULT; void clear_recently_found_dialogs(); DialogId resolve_dialog_username(const string &username); DialogId search_public_dialog(const string &username_to_search, bool force, Promise &&promise); Result process_input_message_text( DialogId dialog_id, tl_object_ptr &&input_message_content, bool is_bot, bool for_draft = false) const TD_WARN_UNUSED_RESULT; static Result> process_input_message_location( tl_object_ptr &&input_message_content) TD_WARN_UNUSED_RESULT; static Result process_input_message_venue(tl_object_ptr &&input_message_content) TD_WARN_UNUSED_RESULT; static Result process_input_message_contact( tl_object_ptr &&input_message_content) TD_WARN_UNUSED_RESULT; Result process_input_message_game(tl_object_ptr &&input_message_content) const TD_WARN_UNUSED_RESULT; static Status fix_text_message(string &text, vector &entities, tl_object_ptr &&parse_mode, bool allow_empty, bool skip_new_entities, bool skip_bot_commands, bool for_draft) TD_WARN_UNUSED_RESULT; Result send_message(DialogId dialog_id, MessageId reply_to_message_id, bool disable_notification, bool from_background, tl_object_ptr &&reply_markup, tl_object_ptr &&input_message_content) TD_WARN_UNUSED_RESULT; Result> send_message_group( DialogId dialog_id, MessageId reply_to_message_id, bool disable_notification, bool from_background, vector> &&input_message_contents) TD_WARN_UNUSED_RESULT; Result send_bot_start_message(UserId bot_user_id, DialogId dialog_id, const string ¶meter) TD_WARN_UNUSED_RESULT; Result send_inline_query_result_message(DialogId dialog_id, MessageId reply_to_message_id, bool disable_notification, bool from_background, int64 query_id, const string &result_id) TD_WARN_UNUSED_RESULT; Result> forward_messages(DialogId to_dialog_id, DialogId from_dialog_id, vector message_ids, bool disable_notification, bool from_background, bool in_game_share, bool as_album) TD_WARN_UNUSED_RESULT; Result send_dialog_set_ttl_message(DialogId dialog_id, int32 ttl); Status send_screenshot_taken_notification_message(DialogId dialog_id); void edit_message_text(FullMessageId full_message_id, tl_object_ptr &&reply_markup, tl_object_ptr &&input_message_content, Promise &&promise); void edit_message_live_location(FullMessageId full_message_id, tl_object_ptr &&reply_markup, tl_object_ptr &&input_location, Promise &&promise); void edit_message_caption(FullMessageId full_message_id, tl_object_ptr &&reply_markup, const string &caption, Promise &&promise); void edit_message_reply_markup(FullMessageId full_message_id, tl_object_ptr &&reply_markup, Promise &&promise); void edit_inline_message_text(const string &inline_message_id, tl_object_ptr &&reply_markup, tl_object_ptr &&input_message_content, Promise &&promise); void edit_inline_message_live_location(const string &inline_message_id, tl_object_ptr &&reply_markup, tl_object_ptr &&input_location, Promise &&promise); void edit_inline_message_caption(const string &inline_message_id, tl_object_ptr &&reply_markup, const string &caption, Promise &&promise); void edit_inline_message_reply_markup(const string &inline_message_id, tl_object_ptr &&reply_markup, Promise &&promise); void set_game_score(FullMessageId full_message_id, bool edit_message, UserId user_id, int32 score, bool force, Promise &&promise); void set_inline_game_score(const string &inline_message_id, bool edit_message, UserId user_id, int32 score, bool force, Promise &&promise); int64 get_game_high_scores(FullMessageId full_message_id, UserId user_id, Promise &&promise); int64 get_inline_game_high_scores(const string &inline_message_id, UserId user_id, Promise &&promise); void on_get_game_high_scores(int64 random_id, tl_object_ptr &&high_scores); tl_object_ptr get_game_high_scores_object(int64 random_id); void send_dialog_action(DialogId dialog_id, const tl_object_ptr &action, Promise &&promise); void set_dialog_photo(DialogId dialog_id, const tl_object_ptr &photo, Promise &&promise); void set_dialog_title(DialogId dialog_id, const string &title, Promise &&promise); void add_dialog_participant(DialogId dialog_id, UserId user_id, int32 forward_limit, Promise &&promise); void add_dialog_participants(DialogId dialog_id, const vector &user_ids, Promise &&promise); void set_dialog_participant_status(DialogId dialog_id, UserId user_id, const tl_object_ptr &chat_member_status, Promise &&promise); DialogParticipant get_dialog_participant(DialogId dialog_id, UserId user_id, int64 &random_id, bool force, Promise &&promise); std::pair> search_dialog_participants(DialogId dialog_id, const string &query, int32 limit, int64 &random_id, bool force, Promise &&promise); vector get_dialog_administrators(DialogId dialog_id, int left_tries, Promise &&promise); void export_dialog_invite_link(DialogId dialog_id, Promise &&promise); string get_dialog_invite_link(DialogId dialog_id); int64 get_dialog_event_log(DialogId dialog_id, const string &query, int64 from_event_id, int32 limit, const tl_object_ptr &filters, const vector &user_ids, Promise &&promise); void on_get_event_log(int64 random_id, tl_object_ptr &&events); tl_object_ptr get_chat_events_object(int64 random_id); bool have_dialog(DialogId dialog_id) const; bool have_dialog_force(DialogId dialog_id); bool load_dialog(DialogId dialog_id, int left_tries, Promise &&promise); void load_dialogs(vector dialog_ids, Promise &&promise); vector get_dialogs(DialogDate offset, int32 limit, bool force, Promise &&promise); vector search_public_dialogs(const string &query, Promise &&promise); std::pair> search_dialogs(const string &query, int32 limit, Promise &&promise); vector get_common_dialogs(UserId user_id, DialogId offset_dialog_id, int32 limit, bool force, Promise &&promise); bool have_message(FullMessageId full_message_id); bool get_message(FullMessageId full_message_id, Promise &&promise); bool get_messages(DialogId dialog_id, const vector &message_ids, Promise &&promise); void get_messages_from_server(vector &&message_ids, Promise &&promise); bool is_message_edited_recently(FullMessageId full_message_id, int32 seconds); string get_public_message_link(FullMessageId full_message_id, Promise &&promise); void on_get_public_message_link(FullMessageId full_message_id, string url); Status delete_dialog_reply_markup(DialogId dialog_id, MessageId message_id) TD_WARN_UNUSED_RESULT; Status set_dialog_draft_message(DialogId dialog_id, tl_object_ptr &&draft_message) TD_WARN_UNUSED_RESULT; Status toggle_dialog_is_pinned(DialogId dialog_id, bool is_pinned) TD_WARN_UNUSED_RESULT; Status set_pinned_dialogs(vector dialog_ids) TD_WARN_UNUSED_RESULT; Status set_dialog_client_data(DialogId dialog_id, string &&client_data) TD_WARN_UNUSED_RESULT; void create_dialog(DialogId dialog_id, Promise &&promise); DialogId create_new_group_chat(const vector &user_ids, const string &title, int64 &random_id, Promise &&promise); DialogId create_new_channel_chat(const string &title, bool is_megagroup, const string &description, int64 &random_id, Promise &&promise); void create_new_secret_chat(UserId user_id, Promise &&promise); DialogId migrate_dialog_to_megagroup(DialogId dialog_id, Promise &&promise); Status open_dialog(DialogId dialog_id) TD_WARN_UNUSED_RESULT; Status close_dialog(DialogId dialog_id) TD_WARN_UNUSED_RESULT; Status view_messages(DialogId dialog_id, const vector &message_ids, bool force_read) TD_WARN_UNUSED_RESULT; Status open_message_content(FullMessageId full_message_id) TD_WARN_UNUSED_RESULT; static tl_object_ptr get_notification_settings_scope_object( NotificationSettingsScope scope); static tl_object_ptr get_notification_settings_object( const NotificationSettings *notification_settings); const NotificationSettings *get_notification_settings(NotificationSettingsScope scope, Promise &&promise); Status set_notification_settings(NotificationSettingsScope scope, tl_object_ptr &¬ification_settings) TD_WARN_UNUSED_RESULT; void reset_all_notification_settings(); tl_object_ptr get_chat_object(DialogId dialog_id); static tl_object_ptr get_chats_object(const vector &dialogs); tl_object_ptr get_dialog_history(DialogId dialog_id, MessageId from_message_id, int32 offset, int32 limit, int left_tries, bool only_local, Promise &&promise); std::pair> search_dialog_messages(DialogId dialog_id, const string &query, UserId sender_user_id, MessageId from_message_id, int32 offset, int32 limit, const tl_object_ptr &filter, int64 &random_id, bool use_db, Promise &&promise); std::pair> offline_search_messages( DialogId dialog_id, const string &query, int64 from_search_id, int32 limit, const tl_object_ptr &filter, int64 &random_id, Promise<> &&promise); std::pair> search_messages(const string &query, int32 offset_date, DialogId offset_dialog_id, MessageId offset_message_id, int32 limit, int64 &random_id, Promise &&promise); std::pair> search_call_messages(MessageId from_message_id, int32 limit, bool only_missed, int64 &random_id, bool use_db, Promise &&promise); std::pair> search_dialog_recent_location_messages(DialogId dialog_id, int32 limit, int64 &random_id, Promise &&promise); vector get_active_live_location_messages(Promise &&promise); int64 get_dialog_message_by_date(DialogId dialog_id, int32 date, Promise &&promise); void on_get_dialog_message_by_date_success(DialogId dialog_id, int32 date, int64 random_id, vector> &&messages); void on_get_dialog_message_by_date_fail(int64 random_id); tl_object_ptr get_dialog_message_by_date_object(int64 random_id); tl_object_ptr get_message_object(FullMessageId full_message_id); tl_object_ptr get_messages_object(int32 total_count, DialogId dialog_id, const vector &message_ids); tl_object_ptr get_messages_object(int32 total_count, const vector &full_message_ids); void add_pending_update(tl_object_ptr &&update, int32 new_pts, int32 pts_count, bool force_apply, const char *source); void add_pending_channel_update(DialogId dialog_id, tl_object_ptr &&update, int32 new_pts, int32 pts_count, const char *source, bool is_postponed_update = false); bool is_update_about_username_change_received(DialogId dialog_id) const; void on_dialog_photo_updated(DialogId dialog_id); void on_dialog_title_updated(DialogId dialog_id); void on_dialog_username_updated(DialogId dialog_id, const string &old_username, const string &new_username); void on_resolved_username(const string &username, DialogId dialog_id); void drop_username(const string &username); static tl_object_ptr get_input_messages_filter(SearchMessagesFilter filter); static SearchMessagesFilter get_search_messages_filter(const tl_object_ptr &filter); tl_object_ptr get_input_notify_peer(NotificationSettingsScope scope) const; NotificationSettingsScope get_notification_settings_scope( tl_object_ptr &¬ify_peer_ptr) const; NotificationSettingsScope get_notification_settings_scope( const tl_object_ptr &scope) const; void on_update_notify_settings(NotificationSettingsScope scope, tl_object_ptr &&peer_notify_settings); bool get_dialog_report_spam_state(DialogId dialog_id, Promise &&promise); void change_dialog_report_spam_state(DialogId dialog_id, bool is_spam_dialog, Promise &&promise); void report_dialog(DialogId dialog_id, const tl_object_ptr &reason, Promise &&promise); void on_get_peer_settings(DialogId dialog_id, tl_object_ptr &&peer_settings); void before_get_difference(); void after_get_difference(); bool on_get_dialog_error(DialogId dialog_id, const Status &status, const string &source); void on_send_message_get_quick_ack(int64 random_id); void check_send_message_result(int64 random_id, DialogId dialog_id, const telegram_api::Updates *updates_ptr, const char *source); FullMessageId on_send_message_success(int64 random_id, MessageId new_message_id, int32 date, FileId new_file_id, const char *source); void on_send_message_file_part_missing(int64 random_id, int bad_part); void on_send_message_fail(int64 random_id, Status error); void on_upload_message_media_success(DialogId dialog_id, MessageId message_id, tl_object_ptr &&media); void on_upload_message_media_file_part_missing(DialogId dialog_id, MessageId message_id, int bad_part); void on_upload_message_media_fail(DialogId dialog_id, MessageId message_id, Status error); void on_create_new_dialog_success(int64 random_id, tl_object_ptr &&updates, DialogType expected_type, Promise &&promise); void on_create_new_dialog_fail(int64 random_id, Status error, Promise &&promise); void on_get_channel_difference(DialogId dialog_id, int32 request_pts, int32 request_limit, tl_object_ptr &&difference_ptr); void force_create_dialog(DialogId dialog_id, const char *source, bool force_update_dialog_pos = false); void on_get_dialog_success(DialogId dialog_id); void on_get_dialog_fail(DialogId dialog_id, Status &&error); void on_binlog_events(vector &&events); void get_payment_form(FullMessageId full_message_id, Promise> &&promise); void validate_order_info(FullMessageId full_message_id, tl_object_ptr order_info, bool allow_save, Promise> &&promise); void send_payment_form(FullMessageId full_message_id, const string &order_info_id, const string &shipping_option_id, const tl_object_ptr &credentials, Promise> &&promise); void get_payment_receipt(FullMessageId full_message_id, Promise> &&promise); ActorOwn sequence_dispatcher_; private: class PendingPtsUpdate { public: tl_object_ptr update; int32 pts; int32 pts_count; PendingPtsUpdate(tl_object_ptr &&update, int32 pts, int32 pts_count) : update(std::move(update)), pts(pts), pts_count(pts_count) { } }; struct MessageInfo { DialogId dialog_id; MessageId message_id; UserId sender_user_id; int32 date; int32 ttl = 0; int64 random_id = 0; tl_object_ptr forward_header; MessageId reply_to_message_id; UserId via_bot_user_id; int32 views = 0; int32 flags = 0; int32 edit_date = 0; string author_signature; int64 media_album_id = 0; unique_ptr content; tl_object_ptr reply_markup; }; struct MessageForwardInfo { UserId sender_user_id; int32 date = 0; DialogId dialog_id; MessageId message_id; string author_signature; DialogId from_dialog_id; MessageId from_message_id; MessageForwardInfo() = default; MessageForwardInfo(UserId sender_user_id, int32 date, DialogId dialog_id, MessageId message_id, string author_signature, DialogId from_dialog_id, MessageId from_message_id) : sender_user_id(sender_user_id) , date(date) , dialog_id(dialog_id) , message_id(message_id) , author_signature(std::move(author_signature)) , from_dialog_id(from_dialog_id) , from_message_id(from_message_id) { } bool operator==(const MessageForwardInfo &rhs) const { return sender_user_id == rhs.sender_user_id && date == rhs.date && dialog_id == rhs.dialog_id && message_id == rhs.message_id && author_signature == rhs.author_signature && from_dialog_id == rhs.from_dialog_id && from_message_id == rhs.from_message_id; } bool operator!=(const MessageForwardInfo &rhs) const { return !(*this == rhs); } friend StringBuilder &operator<<(StringBuilder &string_builder, const MessageForwardInfo &forward_info) { return string_builder << "MessageForwardInfo[sender " << forward_info.sender_user_id << "(" << forward_info.author_signature << "), source " << forward_info.dialog_id << ", source " << forward_info.message_id << ", from " << forward_info.from_dialog_id << ", from " << forward_info.from_message_id << " at " << forward_info.date << "]"; } }; // Do not forget to update MessagesManager::update_message when this class is changed struct Message { int32 random_y; MessageId message_id; UserId sender_user_id; int32 date = 0; int32 edit_date = 0; int64 random_id = 0; unique_ptr forward_info; MessageId reply_to_message_id; int64 reply_to_random_id = 0; // for send_message UserId via_bot_user_id; string author_signature; bool is_channel_post = false; bool is_outgoing = false; bool is_failed_to_send = false; // TODO replace with error_code bool disable_notification = false; bool contains_mention = false; bool contains_unread_mention = false; bool had_reply_markup = false; // had non-inline reply markup? bool from_background = false; // for send_message bool disable_web_page_preview = false; // for send_message bool clear_draft = false; // for send_message bool in_game_share = false; // for send_message bool have_previous = false; bool have_next = false; bool from_database = false; int32 views = 0; int32 ttl = 0; double ttl_expires_at = 0; int64 media_album_id = 0; unique_ptr content; unique_ptr reply_markup; string public_link; unique_ptr left; unique_ptr right; int32 last_access_date = 0; uint64 send_message_logevent_id = 0; NetQueryRef send_query_ref; DialogId debug_forward_from; template void store(StorerT &storer) const; template void parse(ParserT &parser); }; struct Dialog { DialogId dialog_id; MessageId last_new_message_id; // identifier of the last known server message received from update, there should be // no server messages after it MessageId last_message_id; // identifier of the message after which currently there is no any message, i.e. a // message without a gap after it, memory only MessageId first_database_message_id; // identifier of the first message in the database, needed // until there is no gaps in the database MessageId last_database_message_id; // identifier of the last local or server message, if last_database_message_id // is known and last_message_id is known then last_database_message_id <= // last_message_id std::array first_database_message_id_by_index; // use struct Count? std::array message_count_by_index; int32 server_unread_count = 0; int32 local_unread_count = 0; int32 unread_mention_count = 0; MessageId last_read_inbox_message_id; MessageId last_read_outbox_message_id; MessageId reply_markup_message_id; NotificationSettings notification_settings; unique_ptr draft_message; uint64 save_draft_message_logevent_id = 0; uint64 save_draft_message_logevent_id_generation = 0; MessageId last_read_all_mentions_message_id; // all mentions with a message id not greater than it are implicitly read MessageId max_unavailable_message_id; // maximal unavailable message id for dialogs with cleared/unavailable history int32 last_clear_history_date = 0; MessageId last_clear_history_message_id; int64 order = DEFAULT_ORDER; int64 pinned_order = DEFAULT_ORDER; int32 delete_last_message_date = 0; MessageId deleted_last_message_id; bool is_last_message_deleted_locally = false; bool know_can_report_spam = false; bool can_report_spam = false; bool is_opened = false; bool need_restore_reply_markup = true; bool have_full_history = false; bool is_empty = false; bool is_last_read_inbox_message_id_inited = false; bool is_last_read_outbox_message_id_inited = false; int32 pts = 0; // for channels only std::multimap postponed_channel_updates; // for channels only int32 retry_get_difference_timeout = 1; // for channels only std::unordered_map random_id_to_message_id; // for secret chats only MessageId last_assigned_message_id; // identifier of the last local or yet unsent message, assigned after // application start, used to guarantee that all assigned message identifiers // are different std::unordered_map yet_unsent_message_id_to_persistent_message_id; std::unordered_set deleted_message_ids; std::vector pending_update_new_messages; string client_data; // Load from newest to oldest message MessageId suffix_load_first_message_id_; MessageId suffix_load_query_message_id_; std::vector, std::function>> suffix_load_queries_; bool suffix_load_done_ = false; bool suffix_load_has_query_ = false; bool suffix_load_was_query_ = false; std::unordered_set pending_viewed_message_ids; unique_ptr messages = nullptr; struct MessageOp { enum : int8 { Add, SetPts, Delete, DeleteAll } type; bool from_update; bool have_previous; bool have_next; int32 content_type; MessageId message_id; const char *source; double date; MessageOp(decltype(type) type, MessageId message_id, int32 content_type, bool from_update, bool have_previous, bool have_next, const char *source) : type(type) , from_update(from_update) , have_previous(have_previous) , have_next(have_next) , content_type(content_type) , message_id(message_id) , source(source) , date(G()->server_time()) { } }; vector debug_message_op; Dialog() = default; Dialog(const Dialog &) = delete; Dialog &operator=(const Dialog &) = delete; Dialog(Dialog &&other) = delete; Dialog &operator=(Dialog &&other) = delete; ~Dialog(); template void store(StorerT &storer) const; template void parse(ParserT &parser); }; class MessagesIteratorBase { vector stack_; protected: MessagesIteratorBase() = default; // points iterator to message with greatest id which is less or equal than message_id MessagesIteratorBase(const Message *root, MessageId message_id) { size_t last_right_pos = 0; while (root != nullptr) { // LOG(DEBUG) << "root->message_id = " << root->message_id; stack_.push_back(root); if (root->message_id.get() <= message_id.get()) { // LOG(DEBUG) << "Go right"; last_right_pos = stack_.size(); root = root->right.get(); } else { // LOG(DEBUG) << "Go left"; root = root->left.get(); } } stack_.resize(last_right_pos); } const Message *operator*() const { return stack_.empty() ? nullptr : stack_.back(); } ~MessagesIteratorBase() = default; public: MessagesIteratorBase(const MessagesIteratorBase &) = delete; MessagesIteratorBase &operator=(const MessagesIteratorBase &) = delete; MessagesIteratorBase(MessagesIteratorBase &&other) = default; MessagesIteratorBase &operator=(MessagesIteratorBase &&other) = default; void operator++() { if (stack_.empty()) { return; } const Message *cur = stack_.back(); if (!cur->have_next) { stack_.clear(); return; } if (cur->right == nullptr) { while (true) { stack_.pop_back(); if (stack_.empty()) { return; } const Message *new_cur = stack_.back(); if (new_cur->left.get() == cur) { return; } cur = new_cur; } } cur = cur->right.get(); while (cur != nullptr) { stack_.push_back(cur); cur = cur->left.get(); } } void operator--() { if (stack_.empty()) { return; } const Message *cur = stack_.back(); if (!cur->have_previous) { stack_.clear(); return; } if (cur->left == nullptr) { while (true) { stack_.pop_back(); if (stack_.empty()) { return; } const Message *new_cur = stack_.back(); if (new_cur->right.get() == cur) { return; } cur = new_cur; } } cur = cur->left.get(); while (cur != nullptr) { stack_.push_back(cur); cur = cur->right.get(); } } }; class MessagesIterator : public MessagesIteratorBase { public: MessagesIterator() = default; MessagesIterator(Dialog *d, MessageId message_id) : MessagesIteratorBase(d->messages.get(), message_id) { } Message *operator*() const { return const_cast(MessagesIteratorBase::operator*()); } }; class MessagesConstIterator : public MessagesIteratorBase { public: MessagesConstIterator() = default; MessagesConstIterator(const Dialog *d, MessageId message_id) : MessagesIteratorBase(d->messages.get(), message_id) { } const Message *operator*() const { return MessagesIteratorBase::operator*(); } }; struct PendingSecretMessage { MessageInfo message_info; MultiPromiseActor load_data_multipromise; Promise<> success_promise; }; struct InputMessageContent { unique_ptr content; bool disable_web_page_preview = false; bool clear_draft = false; int32 ttl = 0; UserId via_bot_user_id; InputMessageContent(unique_ptr &&content, bool disable_web_page_preview, bool clear_draft, int32 ttl, UserId via_bot_user_id) : content(std::move(content)) , disable_web_page_preview(disable_web_page_preview) , clear_draft(clear_draft) , ttl(ttl) , via_bot_user_id(via_bot_user_id) { } }; class DeleteAllChannelMessagesFromUserOnServerLogEvent; class DeleteDialogHistoryFromServerLogEvent; class DeleteMessageLogEvent; class DeleteMessagesFromServerLogEvent; class ForwardMessagesLogEvent; class GetChannelDifferenceLogEvent; class ReadAllDialogMentionsOnServerLogEvent; class ReadHistoryOnServerLogEvent; class ReadMessageContentsOnServerLogEvent; class ReorderPinnedDialogsOnServerLogEvent; class SaveDialogDraftMessageOnServerLogEvent; class SendBotStartMessageLogEvent; class SendInlineQueryResultMessageLogEvent; class SendMessageLogEvent; class SendScreenshotTakenNotificationMessageLogEvent; class ToggleDialogIsPinnedOnServerLogEvent; static constexpr size_t MAX_GROUPED_MESSAGES = 10; // server side limit static constexpr int32 MAX_GET_DIALOGS = 100; // server side limit static constexpr int32 MAX_GET_HISTORY = 100; // server side limit static constexpr int32 MAX_SEARCH_MESSAGES = 100; // server side limit static constexpr int32 MIN_SEARCH_PUBLIC_DIALOG_PREFIX_LEN = 5; // server side limit static constexpr int32 MIN_CHANNEL_DIFFERENCE = 10; static constexpr int32 MAX_CHANNEL_DIFFERENCE = 100; static constexpr int32 MAX_BOT_CHANNEL_DIFFERENCE = 100000; // server side limit static constexpr int32 MAX_RECENT_FOUND_DIALOGS = 20; // some reasonable value static constexpr size_t MAX_CAPTION_LENGTH = 200; // server side limit static constexpr size_t MAX_NAME_LENGTH = 255; // server side limit for title and description static constexpr int32 MIN_PINNED_DIALOG_DATE = 2147000000; // some big date static constexpr int32 MAX_PRIVATE_MESSAGE_TTL = 60; // server side limit static constexpr int32 UPDATE_CHANNEL_TO_LONG_FLAG_HAS_PTS = 1 << 0; static constexpr int32 CHANNEL_DIFFERENCE_FLAG_IS_FINAL = 1 << 0; static constexpr int32 CHANNEL_DIFFERENCE_FLAG_HAS_TIMEOUT = 1 << 1; static constexpr int32 DIALOG_FLAG_HAS_PTS = 1 << 0; static constexpr int32 DIALOG_FLAG_HAS_DRAFT = 1 << 1; static constexpr int32 DIALOG_FLAG_IS_PINNED = 1 << 2; static constexpr int32 MAX_MESSAGE_VIEW_DELAY = 1; // seconds static constexpr int32 MIN_SAVE_DRAFT_DELAY = 1; // seconds static constexpr int32 MAX_SAVE_DIALOG_DELAY = 0; // seconds static constexpr int32 DIALOG_UNLOAD_DELAY = 60; // seconds static constexpr int32 USERNAME_CACHE_EXPIRE_TIME = 3 * 86400; static constexpr int32 USERNAME_CACHE_EXPIRE_TIME_SHORT = 900; static constexpr int32 MIN_LIVE_LOCATION_PERIOD = 60; // seconds, server side limit static constexpr int32 MAX_LIVE_LOCATION_PERIOD = 86400; // seconds, server side limit static constexpr int32 MAX_PRELOADED_DIALOGS = 1000; static constexpr const char *DELETE_MESSAGE_USER_REQUEST_SOURCE = "user request"; static constexpr bool DROP_UPDATES = false; void open_dialog(Dialog *d); void close_dialog(Dialog *d); void add_secret_message(unique_ptr pending_secret_message, Promise lock_promise = Auto()); void finish_add_secret_message(unique_ptr pending_secret_message); void fix_message_info_dialog_id(MessageInfo &message_info) const; MessageInfo parse_telegram_api_message(tl_object_ptr message_ptr) const; std::pair> create_message(MessageInfo &&message_info, bool is_channel_message); FullMessageId on_get_message(MessageInfo &&message_info, bool from_update, bool is_channel_message, bool have_previous, bool have_next, const char *source); Result process_input_message_content( DialogId dialog_id, tl_object_ptr &&input_message_content) const; Message *get_message_to_send(Dialog *d, MessageId reply_to_message_id, bool disable_notification, bool from_background, unique_ptr &&content, bool *need_update_dialog_pos, unique_ptr forward_info = nullptr); int64 begin_send_message(DialogId dialog_id, const Message *m); Status can_send_message(DialogId dialog_id) const TD_WARN_UNUSED_RESULT; Status can_send_message_content(DialogId dialog_id, const MessageContent *content, bool is_forward) const TD_WARN_UNUSED_RESULT; bool can_edit_message(DialogId dialog_id, const Message *m, bool is_editing, bool only_reply_markup = false) const; MessageId get_persistent_message_id(const Dialog *d, MessageId message_id) const; MessageId get_reply_to_message_id(Dialog *d, MessageId message_id); bool can_set_game_score(DialogId dialog_id, const Message *m) const; bool check_update_dialog_id(const tl_object_ptr &update, DialogId dialog_id); void process_update(tl_object_ptr &&update); void process_channel_update(tl_object_ptr &&update); void delete_messages_from_updates(const vector &message_ids); void delete_dialog_messages_from_updates(DialogId dialog_id, const vector &message_ids); void do_forward_messages(DialogId to_dialog_id, DialogId from_dialog_id, const vector &messages, const vector &message_ids, int64 logevent_id); Result forward_message(DialogId to_dialog_id, DialogId from_dialog_id, MessageId message_id, bool disable_notification, bool from_background, bool in_game_share) TD_WARN_UNUSED_RESULT; SecretInputMedia get_secret_input_media(const MessageContent *content, tl_object_ptr input_file, BufferSlice thumbnail, int32 layer); tl_object_ptr get_input_invoice(const Invoice &invoice) const; tl_object_ptr get_input_web_document(const Photo &photo) const; tl_object_ptr get_input_media_invoice(const MessageInvoice *message_invoice) const; tl_object_ptr get_input_media(const MessageContent *content, tl_object_ptr input_file, tl_object_ptr input_thumbnail, int32 ttl); void delete_message_content_thumbnail(MessageContent *content); void do_send_media(DialogId dialog_id, Message *m, FileId file_id, FileId thumbnail_file_id, tl_object_ptr input_file, tl_object_ptr input_thumbnail); void do_send_secret_media(DialogId dialog_id, Message *m, FileId file_id, FileId thumbnail_file_id, tl_object_ptr input_encrypted_file, BufferSlice thumbnail); void do_send_message(DialogId dialog_id, Message *m, vector bad_parts = {}); void on_message_media_uploaded(DialogId dialog_id, Message *m, tl_object_ptr &&input_media, FileId file_id, FileId thumbnail_file_id); void on_secret_message_media_uploaded(DialogId dialog_id, Message *m, SecretInputMedia &&secret_input_media, FileId file_id, FileId thumbnail_file_id); void on_upload_message_media_finished(int64 media_album_id, DialogId dialog_id, MessageId message_id, Status result); void do_send_message_group(int64 media_album_id); void on_media_message_ready_to_send(DialogId dialog_id, MessageId message_id, Promise &&promise); void on_yet_unsent_media_queue_updated(DialogId dialog_id); void save_send_bot_start_message_logevent(UserId bot_user_id, DialogId dialog_id, const string ¶meter, Message *m); void do_send_bot_start_message(UserId bot_user_id, DialogId dialog_id, const string ¶meter, Message *m); void save_send_inline_query_result_message_logevent(DialogId dialog_id, Message *m, int64 query_id, const string &result_id); void do_send_inline_query_result_message(DialogId dialog_id, Message *m, int64 query_id, const string &result_id); uint64 save_send_screenshot_taken_notification_message_logevent(DialogId dialog_id, const Message *m); void do_send_screenshot_taken_notification_message(DialogId dialog_id, const Message *m, uint64 logevent_id); Message *continue_send_message(DialogId dialog_id, unique_ptr &&m, uint64 logevent_id); tl_object_ptr get_input_chat_photo(FileId file_id) const; bool is_message_unload_enabled() const; static bool is_allowed_media_group_content(int32 content_type); static bool can_forward_message(DialogId from_dialog_id, const Message *m); static bool is_service_message_content(int32 content_type); static bool can_delete_channel_message(DialogParticipantStatus status, const Message *m, bool is_bot); bool can_revoke_message(DialogId dialog_id, const Message *m) const; bool can_unload_message(const Dialog *d, const Message *m) const; void unload_message(Dialog *d, MessageId message_id); unique_ptr delete_message(Dialog *d, MessageId message_id, bool is_permanently_deleted, bool *need_update_dialog_pos, const char *source); unique_ptr do_delete_message(Dialog *d, MessageId message_id, bool is_permanently_deleted, bool only_from_memory, bool *need_update_dialog_pos, const char *source); void unload_dialog(DialogId dialog_id); void delete_all_dialog_messages(Dialog *d, bool remove_from_dialog_list, bool is_permanent); void do_delete_all_dialog_messages(Dialog *d, unique_ptr &m, vector &deleted_message_ids); void delete_messages_from_server(DialogId dialog_id, vector message_ids, bool revoke, uint64 logevent_id, Promise &&promise); void delete_dialog_history_from_server(DialogId dialog_id, MessageId max_message_id, bool remove_from_dialog_list, bool allow_error, uint64 logevent_id, Promise &&promise); void delete_all_channel_messages_from_user_on_server(ChannelId channel_id, UserId user_id, uint64 logevent_id, Promise &&promise); void read_all_dialog_mentions_on_server(DialogId dialog_id, uint64 logevent_id, Promise &&promise); static MessageId find_message_by_date(const unique_ptr &m, int32 date); static void find_messages_from_user(const unique_ptr &m, UserId user_id, vector &message_ids); static void find_unread_mentions(const unique_ptr &m, vector &message_ids); static void find_old_messages(const unique_ptr &m, MessageId max_message_id, vector &message_ids); void find_unloadable_messages(const Dialog *d, int32 unload_before_date, const unique_ptr &m, vector &message_ids, int32 &left_to_unload) const; bool message_views_enabled(DialogId dialog_id) const; bool update_message_views(DialogId dialog_id, Message *m, int32 views); bool update_message_contains_unread_mention(Dialog *d, Message *m, bool contains_unread_mention); static bool update_opened_message_content(Message *m); void read_message_content_from_updates(MessageId message_id); void read_channel_message_content_from_updates(Dialog *d, MessageId message_id); bool read_message_content(Dialog *d, Message *m, bool is_local_read); void read_message_contents_on_server(DialogId dialog_id, vector message_ids, uint64 logevent_id); void read_history_inbox(DialogId dialog_id, MessageId max_message_id, int32 unread_count, const char *source); void read_history_outbox(DialogId dialog_id, MessageId max_message_id, int32 read_date = -1); void read_history_on_server(DialogId dialog_id, MessageId max_message_id, bool allow_error, uint64 logevent_id); void read_secret_chat_outbox_inner(DialogId dialog_id, int32 up_to_date, int32 read_date); void set_dialog_max_unavailable_message_id(DialogId dialog_id, MessageId max_unavailable_message_id, bool from_update); void preload_newer_messages(const Dialog *d, MessageId max_message_id); void preload_older_messages(const Dialog *d, MessageId min_message_id); void on_get_history_from_database(DialogId dialog_id, MessageId from_message_id, int32 offset, int32 limit, bool from_the_end, bool only_local, vector &&messages, Promise &&promise); void get_history_from_the_end(DialogId dialog_id, bool from_database, bool only_local, Promise &&promise); void get_history(DialogId dialog_id, MessageId from_message_id, int32 offset, int32 limit, bool from_database, bool only_local, Promise &&promise); void load_messages(DialogId dialog_id, MessageId from_message_id, int32 offset, int32 limit, int left_tries, bool only_local, Promise &&promise); static int32 get_random_y(MessageId message_id); bool is_allowed_useless_update(const tl_object_ptr &update) const; bool is_message_auto_read(DialogId dialog_id, bool is_outgoing, bool only_content) const; void fail_send_message(FullMessageId full_message_id, int error_code, const string &error_message); void on_dialog_updated(DialogId dialog_id, const char *source); BufferSlice get_dialog_database_value(const Dialog *d); void save_dialog_to_database(DialogId dialog_id); void on_save_dialog_to_database(DialogId dialog_id, bool success); void load_dialog_list(Promise &&promise); void load_dialog_list_from_database(int32 limit, Promise &&promise); static void preload_dialog_list(void *messages_manager_void); void update_message_count_by_index(Dialog *d, int diff, const Message *m); int32 get_message_index_mask(DialogId dialog_id, const Message *m) const; int32 get_message_content_index_mask(const MessageContent *content, bool is_secret, bool is_outgoing) const; Message *add_message_to_dialog(DialogId dialog_id, unique_ptr message, bool from_update, bool *need_update, bool *need_update_dialog_pos, const char *source); Message *add_message_to_dialog(Dialog *d, unique_ptr message, bool from_update, bool *need_update, bool *need_update_dialog_pos, const char *source); void add_message_to_database(const Dialog *d, const Message *m, const char *source); void delete_all_dialog_messages_from_database(DialogId dialog_id, MessageId message_id, const char *source); void delete_message_from_database(Dialog *d, MessageId message_id, const Message *m, bool is_permanently_deleted) const; void delete_message_files(const Message *m) const; void do_delete_message_logevent(const DeleteMessageLogEvent &logevent) const; void attach_message_to_previous(Dialog *d, MessageId message_id); void attach_message_to_next(Dialog *d, MessageId message_id); void update_message(Dialog *d, unique_ptr &old_message, unique_ptr new_message, bool need_send_update_message_content, bool *need_update_dialog_pos); bool need_message_text_changed_warning(const Message *old_message, const MessageText *old_content, const MessageText *new_content); bool update_message_content(DialogId dialog_id, const Message *old_message, unique_ptr &old_content, unique_ptr new_content, bool need_send_update_message_content); void send_update_new_message(Dialog *d, const Message *m, bool force = false); void flush_pending_update_new_messages(DialogId dialog_id); void send_update_message_send_succeeded(Dialog *d, MessageId old_message_id, const Message *m) const; void send_update_message_content(DialogId dialog_id, MessageId message_id, const MessageContent *content, const char *source) const; void send_update_message_edited(FullMessageId full_message_id) const; void send_update_message_edited(DialogId dialog_id, const Message *m) const; void send_update_delete_messages(DialogId dialog_id, vector &&message_ids, bool is_permanent, bool from_cache) const; void send_update_chat(Dialog *d); void send_update_chat_draft_message(const Dialog *d); void send_update_chat_last_message(Dialog *d, const char *source); void send_update_chat_read_inbox(const Dialog *d, bool force, const char *source); void send_update_chat_read_outbox(const Dialog *d); void send_update_chat_unread_mention_count(const Dialog *d); tl_object_ptr get_message_object(DialogId dialog_id, const Message *message) const; static tl_object_ptr get_messages_object(int32 total_count, vector> &&messages); void set_dialog_last_read_inbox_message_id(Dialog *d, MessageId message_id, int32 server_unread_count, int32 local_unread_count, bool force_update, const char *source); void set_dialog_last_read_outbox_message_id(Dialog *d, MessageId message_id); void set_dialog_last_message_id(Dialog *d, MessageId last_message_id, const char *source); void set_dialog_first_database_message_id(Dialog *d, MessageId first_database_message_id, const char *source); void set_dialog_last_database_message_id(Dialog *d, MessageId last_database_message_id, const char *source); void set_dialog_last_new_message_id(Dialog *d, MessageId last_new_message_id, const char *source); void set_dialog_last_clear_history_date(Dialog *d, int32 date, MessageId last_clear_history_message_id, const char *source); void set_dialog_is_empty(Dialog *d, const char *source); static int32 get_pinned_dialogs_limit(); static vector remove_secret_chat_dialog_ids(vector dialog_ids); void set_dialog_is_pinned(Dialog *d, bool is_pinned); void toggle_dialog_is_pinned_on_server(DialogId dialog_id, bool is_pinned, uint64 logevent_id); void reorder_pinned_dialogs_on_server(const vector &dialog_ids, uint64 logevent_id); void set_dialog_reply_markup(Dialog *d, MessageId message_id); void try_restore_dialog_reply_markup(Dialog *d, const Message *m); static string get_notification_settings_scope_database_key(NotificationSettingsScope scope); bool update_notification_settings(NotificationSettingsScope scope, NotificationSettings *current_settings, const NotificationSettings &new_settings); Dialog *get_dialog_by_message_id(MessageId message_id); MessageId get_message_id_by_random_id(Dialog *d, int64 random_id); Dialog *add_dialog(DialogId dialog_id); Dialog *add_new_dialog(unique_ptr &&d, bool is_loaded_from_database); void add_dialog_last_database_message(Dialog *d, unique_ptr &&last_database_message); tl_object_ptr get_input_message_text_object( const InputMessageText &input_message_text) const; tl_object_ptr get_draft_message_object(const unique_ptr &draft_message) const; tl_object_ptr get_chat_type_object(DialogId dialog_id) const; tl_object_ptr get_chat_object(const Dialog *d); bool have_dialog_info(DialogId dialog_id) const; Dialog *get_dialog(DialogId dialog_id); const Dialog *get_dialog(DialogId dialog_id) const; Dialog *get_dialog_force(DialogId dialog_id); Dialog *on_load_dialog_from_database(const Result &r_value); void on_get_dialogs_from_database(vector &&dialogs, Promise &&promise); void send_get_dialog_query(DialogId dialog_id, Promise &&promise); void send_search_public_dialogs_query(const string &query, Promise &&promise); vector get_pinned_dialogs() const; void update_dialogs_hints(const Dialog *d); void update_dialogs_hints_rating(const Dialog *d); std::pair> search_private_chat_participants(UserId my_user_id, UserId peer_user_id, const string &query, int32 limit) const; static unique_ptr *find_message(unique_ptr *v, MessageId message_id); static const unique_ptr *find_message(const unique_ptr *v, MessageId message_id); static Message *get_message(Dialog *d, MessageId message_id); static const Message *get_message(const Dialog *d, MessageId message_id); Message *get_message(FullMessageId full_message_id); const Message *get_message(FullMessageId full_message_id) const; Message *get_message_force(Dialog *d, MessageId message_id); Message *get_message_force(FullMessageId full_message_id); Message *on_get_message_from_database(DialogId dialog_id, Dialog *d, const BufferSlice &value); void get_dialog_message_by_date_from_server(const Dialog *d, int32 date, int64 random_id, bool after_database_search, Promise &&promise); void on_get_dialog_message_by_date_from_database(DialogId dialog_id, int32 date, int64 random_id, Result result, Promise promise); static NotificationSettings get_notification_settings( tl_object_ptr &¬ification_settings); const NotificationSettings *get_dialog_notification_settings(const Dialog *d, DialogId dialog_id) const; NotificationSettings *get_notification_settings(NotificationSettingsScope scope, bool force); static unique_ptr get_draft_message(tl_object_ptr &&draft_message_ptr); static string get_media_caption(const string &message_text, string &&caption); Photo get_web_document_photo(tl_object_ptr web_document, DialogId owner_dialog_id) const; unique_ptr get_secret_message_document( tl_object_ptr file, tl_object_ptr &&document, vector> &&attributes, DialogId owner_dialog_id, string &&caption, bool is_opened) const; unique_ptr get_message_document(tl_object_ptr &&document, DialogId owner_dialog_id, string &&caption, bool is_opened, MultiPromiseActor *load_data_multipromise_ptr) const; unique_ptr get_message_document(std::pair &&parsed_document, string &&caption, bool is_opened) const; unique_ptr get_message_photo(tl_object_ptr &&photo, DialogId owner_dialog_id, string &&caption) const; unique_ptr get_secret_message_content( string message_text, tl_object_ptr file, tl_object_ptr &&media, vector> &&secret_entities, DialogId owner_dialog_id, MultiPromiseActor &load_data_multipromise) const; unique_ptr get_message_content(string message_text, tl_object_ptr &&media, vector> &&server_entities, DialogId owner_dialog_id, bool is_content_read, UserId via_bot_user_id, int32 *ttl) const; unique_ptr dup_message_content(DialogId dialog_id, const MessageContent *content, bool for_forward); unique_ptr get_message_action_content(tl_object_ptr &&action, DialogId owner_dialog_id, MessageId reply_to_message_id) const; tl_object_ptr get_message_content_object(const MessageContent *content) const; int32 get_message_content_duration(const MessageContent *content) const; static FileId get_message_content_file_id(const MessageContent *content); FileId get_message_content_thumbnail_file_id(const MessageContent *content) const; vector get_message_file_ids(const Message *message) const; void cancel_send_message_query(DialogId dialog_id, unique_ptr &m); static int32 get_message_flags(const Message *m); unique_ptr get_message_forward_info( tl_object_ptr &&forward_header); static tl_object_ptr get_message_forward_info_object( const unique_ptr &forward_info); void ttl_read_history_inbox(DialogId dialog_id, MessageId from_message_id, MessageId till_message_id, double timestamp); void ttl_read_history_outbox(DialogId dialog_id, MessageId from_message_id, MessageId till_message_id, double timestamp); void ttl_on_view(const Dialog *d, Message *message, double view_date, double now); bool ttl_on_open(Dialog *d, Message *message, double now, bool is_local_read); void ttl_register_message(DialogId dialog_id, const Message *message, double now); void ttl_unregister_message(DialogId dialog_id, const Message *message, double now); void ttl_loop(double now); void ttl_update_timeout(double now); void on_message_ttl_expired(Dialog *d, Message *message); void on_message_ttl_expired_impl(Dialog *d, Message *message); void start_up() override; void loop() override; void tear_down() override; void ttl_db_loop_start(double server_now); void ttl_db_loop(double server_now); void ttl_db_on_result(Result>, int32>> r_result, bool dummy); static MessageId get_first_database_message_id_by_index(const Dialog *d, SearchMessagesFilter filter); void on_search_dialog_messages_db_result(int64 random_id, DialogId dialog_id, MessageId from_message_id, MessageId first_db_message_id, SearchMessagesFilter filter_type, int32 offset, int32 limit, Result result, Promise<> promise); void on_messages_db_fts_result(Result result, int64 random_id, Promise<> &&promise); void on_messages_db_calls_result(Result result, int64 random_id, MessageId first_db_message_id, SearchMessagesFilter filter, Promise<> &&promise); void on_load_active_live_location_full_message_ids_from_database(string value); void on_load_active_live_location_messages_finished(); void try_add_active_live_location(DialogId dialog_id, const Message *m); void add_active_live_location(FullMessageId full_message_id); bool delete_active_live_location(DialogId dialog_id, const Message *m); void save_active_live_locations(); Result> get_dialog_reply_markup( DialogId dialog_id, tl_object_ptr &&reply_markup_ptr) const TD_WARN_UNUSED_RESULT; const DialogPhoto *get_dialog_photo(DialogId dialog_id) const; string get_dialog_title(DialogId dialog_id) const; string get_dialog_username(DialogId dialog_id) const; static int64 get_dialog_order(MessageId message_id, int32 message_date); bool update_dialog_draft_message(Dialog *d, unique_ptr &&draft_message, bool from_update, bool need_update_dialog_pos); void save_dialog_draft_message_on_server(DialogId dialog_id); void on_saved_dialog_draft_message(DialogId dialog_id, uint64 generation); int64 get_next_pinned_dialog_order(); void update_dialog_pos(Dialog *d, bool remove_from_dialog_list, const char *source, bool need_send_update_chat_order = true); bool set_dialog_order(Dialog *d, int64 new_order, bool need_send_update_chat_order); void update_last_dialog_date(); void load_notification_settings(); void set_get_difference_timeout(double timeout); void skip_old_pending_update(tl_object_ptr &&update, int32 new_pts, int32 old_pts, int32 pts_count, const char *source); void process_pending_updates(); void drop_pending_updates(); static string get_channel_pts_key(DialogId dialog_id); int32 load_channel_pts(DialogId dialog_id) const; void set_channel_pts(Dialog *d, int32 new_pts, const char *source) const; bool running_get_channel_difference(DialogId dialog_id) const; void get_channel_difference(DialogId dialog_id, int32 pts, bool force, const char *source); void do_get_channel_difference(DialogId dialog_id, int32 pts, bool force, tl_object_ptr &&input_channel, const char *source); void process_get_channel_difference_updates(DialogId dialog_id, vector> &&new_messages, vector> &&other_updates); void on_get_channel_dialog(DialogId dialog_id, MessageId last_message_id, MessageId read_inbox_max_message_id, int32 server_unread_count, int32 unread_mention_count, MessageId read_outbox_max_message_id, vector> &&messages); void after_get_channel_difference(DialogId dialog_id, bool success); static void on_channel_get_difference_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int); static void on_pending_message_views_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int); static void on_pending_draft_message_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int); static void on_pending_updated_dialog_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int); static void on_pending_unload_dialog_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int); void load_secret_thumbnail(FileId thumbnail_file_id); static tl_object_ptr get_channel_admin_log_events_filter( const tl_object_ptr &filters); tl_object_ptr get_chat_event_action_object( tl_object_ptr &&action_ptr); void on_upload_media(FileId file_id, tl_object_ptr input_file, tl_object_ptr input_encrypted_file); void on_upload_media_error(FileId file_id, Status status); void on_load_secret_thumbnail(FileId thumbnail_file_id, BufferSlice thumbnail); void on_upload_thumbnail(FileId thumbnail_file_id, tl_object_ptr thumbnail_input_file); void on_upload_dialog_photo(FileId file_id, tl_object_ptr input_file); void on_upload_dialog_photo_error(FileId file_id, Status status); static uint64 get_sequence_dispatcher_id(DialogId dialog_id, int32 message_content_type); Dialog *get_service_notifications_dialog(); static MessageId get_next_message_id(Dialog *d, int32 type); static MessageId get_next_local_message_id(Dialog *d); static MessageId get_next_yet_unsent_message_id(Dialog *d); bool add_recently_found_dialog_internal(DialogId dialog_id); bool remove_recently_found_dialog_internal(DialogId dialog_id); void save_recently_found_dialogs(); bool load_recently_found_dialogs(Promise &promise); void update_used_hashtags(DialogId dialog_id, const Message *m); string get_search_text(const Message *m); unique_ptr parse_dialog(DialogId dialog_id, const BufferSlice &value); void load_calls_db_state(); void save_calls_db_state(); static constexpr bool is_debug_message_op_enabled(); static void dump_debug_message_op(const Dialog *d, int priority = 0); void add_message_dependencies(Dependencies &dependencies, DialogId dialog_id, const Message *m); void add_dialog_dependencies(Dependencies &dependencies, DialogId dialog_id); void resolve_dependencies_force(const Dependencies &dependencies); void save_send_message_logevent(DialogId dialog_id, Message *m); void suffix_load_loop(Dialog *d); void suffix_load_update_first_message_id(Dialog *d); void suffix_load_query_ready(DialogId dialog_id); void suffix_load_add_query(Dialog *d, std::pair, std::function> query); void suffix_load_till_date(Dialog *d, int32 date, Promise<> promise); void suffix_load_till_message_id(Dialog *d, MessageId message_id, Promise<> promise); Result get_invoice_message_id(FullMessageId full_message_id); bool is_broadcast_channel(DialogId dialog_id) const; int32 recently_found_dialogs_loaded_ = 0; // 0 - not loaded, 1 - load request was sent, 2 - loaded MultiPromiseActor resolve_recent_found_dialogs_multipromise_; vector recently_found_dialog_ids_; class UploadMediaCallback; class UploadThumbnailCallback; class UploadDialogPhotoCallback; std::shared_ptr upload_media_callback_; std::shared_ptr upload_thumbnail_callback_; std::shared_ptr upload_dialog_photo_callback_; int32 accumulated_pts_count_ = 0; int32 accumulated_pts_ = -1; Timeout pts_gap_timeout_; std::unordered_map, FileIdHash> being_uploaded_files_; // file_id -> message, thumbnail_file_id struct UploadedThumbnailInfo { FullMessageId full_message_id; FileId file_id; // original file file_id tl_object_ptr input_file; // original file InputFile }; std::unordered_map being_uploaded_thumbnails_; // thumbnail_file_id -> ... struct UploadedSecretThumbnailInfo { FullMessageId full_message_id; FileId file_id; // original file file_id tl_object_ptr input_file; // original file InputEncryptedFile }; std::unordered_map being_loaded_secret_thumbnails_; // thumbnail_file_id -> ... // TTL class TtlNode : private HeapNode { public: TtlNode(DialogId dialog_id, MessageId message_id) : full_message_id(dialog_id, message_id) { } FullMessageId full_message_id; HeapNode *as_heap_node() const { return const_cast(static_cast(this)); } static TtlNode *from_heap_node(HeapNode *node) { return static_cast(node); } bool operator==(const TtlNode &other) const { return full_message_id == other.full_message_id; } }; struct TtlNodeHash { std::size_t operator()(const TtlNode &ttl_node) const { return FullMessageIdHash()(ttl_node.full_message_id); } }; std::unordered_set ttl_nodes_; KHeap ttl_heap_; Slot ttl_slot_; enum YieldType { None, Ttl, TtlDb }; // None should be first int32 ttl_db_expire_from_; int32 ttl_db_expire_till_; bool ttl_db_has_query_; Slot ttl_db_slot_; std::unordered_set message_random_ids_; std::unordered_map being_sent_messages_; // message_random_id -> message std::unordered_map update_message_ids_; // full_message_id -> temporary_id std::unordered_map debug_being_sent_messages_; // message_random_id -> dialog_id struct UploadedDialogPhotoInfo { Promise promise; DialogId dialog_id; }; std::unordered_map uploaded_dialog_photos_; // file_id -> ... struct PendingMessageGroupSend { DialogId dialog_id; size_t finished_count = 0; vector message_ids; vector is_finished; vector results; }; std::unordered_map pending_message_group_sends_; // media_album_id -> ... std::unordered_map message_id_to_dialog_id_; std::unordered_map last_clear_history_message_id_to_dialog_id_; std::unordered_map created_dialogs_; // random_id -> dialog_id std::unordered_map, DialogIdHash> pending_created_dialogs_; // dialog_id -> promise bool running_get_difference_ = false; // true after before_get_difference and false after after_get_difference std::unordered_map, DialogIdHash> dialogs_; std::multimap pending_updates_; std::multimap postponed_pts_updates_; std::unordered_set loaded_dialogs_; // dialogs loaded from database, but not added to dialogs_ std::unordered_set postponed_chat_read_inbox_updates_; std::unordered_map>>, DialogIdHash> postponed_get_message_requests_; std::unordered_map>> search_public_dialogs_queries_; std::unordered_map> found_public_dialogs_; // TODO time bound cache std::unordered_map, UserIdHash> found_common_dialogs_; // TODO time bound cache std::unordered_map get_dialog_message_by_date_results_; std::unordered_map>> found_dialog_messages_; // random_id -> [total_count, [message_id]...] std::unordered_map>> found_messages_; // random_id -> [total_count, [full_message_id]...] std::unordered_map>> found_call_messages_; // random_id -> [total_count, [full_message_id]...] std::unordered_map>> found_dialog_recent_location_messages_; // random_id -> [total_count, [message_id]...] std::unordered_map>> found_fts_messages_; // random_id -> [from_search_id, [full_message_id]...] std::unordered_map> chat_events_; // random_id -> chat events std::unordered_map> game_high_scores_; // random_id -> high scores std::unordered_map>, DialogIdHash> get_dialog_queries_; std::unordered_map replied_by_yet_unsent_messages_; std::unordered_set waiting_for_web_page_messages_; NotificationSettings users_notification_settings_; NotificationSettings chats_notification_settings_; NotificationSettings dialogs_notification_settings_; // uint32 preloaded_dialogs_ = 0; // TODO remove variable int64 current_pinned_dialog_order_ = DEFAULT_ORDER; std::set ordered_dialogs_; std::set ordered_server_dialogs_; // date of last dialog in the dialog list // last_dialog_date_ == min(last_server_dialog_date_, last_secret_chat_dialog_date_) DialogDate last_dialog_date_ = MIN_DIALOG_DATE; // in memory // date of last known user/group/channel dialog in the right order DialogDate last_server_dialog_date_ = MIN_DIALOG_DATE; DialogDate last_loaded_database_dialog_date_ = MIN_DIALOG_DATE; DialogDate last_database_server_dialog_date_ = MIN_DIALOG_DATE; MultiPromiseActor load_dialog_list_multipromise_; // should be defined before pending_on_get_dialogs_ Timeout preload_dialog_list_timeout_; std::unordered_set active_get_channel_differencies_; std::unordered_map get_channel_difference_to_logevent_id_; MultiTimeout channel_get_difference_timeout_; MultiTimeout channel_get_difference_retry_timeout_; MultiTimeout pending_message_views_timeout_; MultiTimeout pending_draft_message_timeout_; MultiTimeout pending_updated_dialog_timeout_; MultiTimeout pending_unload_dialog_timeout_; Hints dialogs_hints_; // search dialogs by title and username std::unordered_set active_live_location_full_message_ids_; bool are_active_live_location_messages_loaded_ = false; vector> load_active_live_location_messages_queries_; struct ResolvedUsername { DialogId dialog_id; double expires_at; }; std::unordered_map resolved_usernames_; std::unordered_map unaccessible_resolved_usernames_; struct PendingOnGetDialogs { vector> dialogs; int32 total_count; vector> messages; Promise promise; }; vector pending_on_get_dialogs_; std::unordered_map pending_channel_on_get_dialogs_; ChangesProcessor> pending_secret_messages_; std::unordered_map, DialogIdHash> pending_add_dialog_last_database_message_dependent_dialogs_; std::unordered_map>, DialogIdHash> pending_add_dialog_last_database_message_; // dialog -> dependency counter + message CallsDbState calls_db_state_; std::unordered_map>> yet_unsent_media_queues_; Td *td_; ActorShared<> parent_; }; } // namespace td