diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index aefd6b0e6..6351507e0 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -248,10 +248,10 @@ chatPhoto small:file big:file = ChatPhoto; //@description The phone number of user A is not known to user B linkStateNone = LinkState; -//@description The phone number of user A is known but that number has not been saved to the contacts list of user B +//@description The phone number of user A is known but that number has not been saved to the contact list of user B linkStateKnowsPhoneNumber = LinkState; -//@description The phone number of user A has been saved to the contacts list of user B +//@description The phone number of user A has been saved to the contact list of user B linkStateIsContact = LinkState; @@ -1803,6 +1803,26 @@ checkChatUsernameResultPublicChatsTooMuch = CheckChatUsernameResult; checkChatUsernameResultPublicGroupsUnavailable = CheckChatUsernameResult; +//@class NotificationType @description Contains detailed information about a notification + +//@description New message was received @message The message +notificationTypeNewMessage message:message = NotificationType; + +//@description New secret chat was created +notificationTypeNewSecretChat = NotificationType; + +//@description New incoming call was received @call_id Call identifier +notificationTypeNewIncomingCall call_id:int32 = NotificationType; + + +//@description Contains information about a notification @id Unique persistent identifier of this notification @type Notification type +notification id:int32 type:NotificationType = Notification; + +//@description Describes a group of notifications @id Unique persistent auto-incremented from 1 identifier of the notification group @chat_id Identifier of a chat to which all notifications in the group belong +//@total_count Total number of active notifications in the group @notifications The list of active notifications +notificationGroup id:int32 chat_id:int53 total_count:int32 notifications:vector = NotificationGroup; + + //@class OptionValue @description Represents the value of an option //@description Boolean option @value The value of the option @@ -2118,8 +2138,8 @@ inputSticker png_sticker:InputFile emojis:string mask_position:maskPosition = In //@description The user authorization state has changed @authorization_state New authorization state updateAuthorizationState authorization_state:AuthorizationState = Update; -//@description A new message was received; can also be an outgoing message @message The new message @disable_notification True, if this message must not generate a notification @contains_mention True, if the message contains a mention of the current user -updateNewMessage message:message disable_notification:Bool contains_mention:Bool = Update; +//@description A new message was received; can also be an outgoing message @message The new message +updateNewMessage message:message = Update; //@description A request to send a message has reached the Telegram server. This doesn't mean that the message will be sent successfully or even that the send message request will be processed. This update will be sent only if the option "use_quick_ack" is set to true. This update may be sent multiple times for the same message //@chat_id The chat identifier of the sent message @message_id A temporary message identifier @@ -2159,7 +2179,7 @@ updateChatPhoto chat_id:int53 photo:chatPhoto = Update; //@description The last message of a chat was changed. If last_message is null then the last message in the chat became unknown. Some new unknown messages might be added to the chat in this case @chat_id Chat identifier @last_message The new last message in the chat; may be null @order New value of the chat order updateChatLastMessage chat_id:int53 last_message:message order:int64 = Update; -//@description The order of the chat in the chats list has changed. Instead of this update updateChatLastMessage, updateChatIsPinned or updateChatDraftMessage might be sent @chat_id Chat identifier @order New value of the order +//@description The order of the chat in the chat list has changed. Instead of this update updateChatLastMessage, updateChatIsPinned or updateChatDraftMessage might be sent @chat_id Chat identifier @order New value of the order updateChatOrder chat_id:int53 order:int64 = Update; //@description A chat was pinned or unpinned @chat_id Chat identifier @is_pinned New value of is_pinned @order New value of the chat order @@ -2196,6 +2216,14 @@ updateChatReplyMarkup chat_id:int53 reply_markup_message_id:int53 = Update; //@description A chat draft has changed. Be aware that the update may come in the currently opened chat but with old content of the draft. If the user has changed the content of the draft, this update shouldn't be applied @chat_id Chat identifier @draft_message The new draft message; may be null @order New value of the chat order updateChatDraftMessage chat_id:int53 draft_message:draftMessage order:int64 = Update; +//@description A list of active notifications in a notification group has changed @notification_group_id Unique notification group identifier @chat_id Identifier of a chat to which all notifications in the group belong +//@notification_settings_chat_id Chat identifier, which notification settings must be applied @silent True, if the notifications should be shown without sound +//@total_count Total number of active notifications in the group @new_notifications List of new group notifications @edited_notifications List of edited group notifications @deleted_notification_ids Identifiers of deleted group notifications +updateNotificationGroup chat_id:int53 notification_group_id:int32 notification_settings_chat_id:int53 silent:Bool total_count:int32 new_notifications:vector edited_notifications:vector deleted_notification_ids:vector = Update; + +//@description Contains active notifications that was shown on previous application launches. This update is sent only if a message database is used. In that case it comes once before any updateNotificationGroup update @groups Lists of active notification groups +updateActiveNotifications groups:vector = Update; + //@description Some messages were deleted @chat_id Chat identifier @message_ids Identifiers of the deleted messages //@is_permanent True, if the messages are permanently deleted by a user (as opposed to just becoming unaccessible) //@from_cache True, if the messages are deleted only from the cache and can possibly be retrieved again in the future @@ -2515,7 +2543,7 @@ removeRecentlyFoundChat chat_id:int53 = Ok; clearRecentlyFoundChats = Ok; //@description Checks whether a username can be set for a chat @chat_id Chat identifier; should be identifier of a supergroup chat, or a channel chat, or a private chat with self, or zero if chat is being created @username Username to be checked -checkChatUsername chat_id:int64 username:string = CheckChatUsernameResult; +checkChatUsername chat_id:int53 username:string = CheckChatUsernameResult; //@description Returns a list of public chats created by the user getCreatedPublicChats = Chats; @@ -2534,7 +2562,7 @@ getGroupsInCommon user_id:int32 offset_chat_id:int53 limit:int32 = Chats; //@only_local If true, returns only messages that are available locally without sending network requests getChatHistory chat_id:int53 from_message_id:int53 offset:int32 limit:int32 only_local:Bool = Messages; -//@description Deletes all messages in the chat only for the user. Cannot be used in channels and public supergroups @chat_id Chat identifier @remove_from_chat_list Pass true if the chat should be removed from the chats list +//@description Deletes all messages in the chat only for the user. Cannot be used in channels and public supergroups @chat_id Chat identifier @remove_from_chat_list Pass true if the chat should be removed from the chat list deleteChatHistory chat_id:int53 remove_from_chat_list:Bool = Ok; //@description Searches for messages with given words in the chat. Returns the results in reverse chronological order, i.e. in order of decreasing message_id. Cannot be used in secret chats with a non-empty query @@ -2582,6 +2610,13 @@ getChatMessageByDate chat_id:int53 date:int32 = Message; getChatMessageCount chat_id:int53 filter:SearchMessagesFilter return_local:Bool = Count; +//@description Removes an active notification from notification list @notification_id Identifier of removed notification +removeNotification notification_id:int32 = Ok; + +//@description Removes group of active notifications @notification_group_id Notification group identifier @max_notification_id Maximum identifier of removed notifications +removeNotifications notification_group_id:int32 max_notification_id:int32 = Ok; + + //@description Returns a public HTTPS link to a message. Available only for messages in public supergroups and channels //@chat_id Identifier of the chat to which the message belongs //@message_id Identifier of the message @@ -2928,7 +2963,7 @@ getContacts = Users; //@description Searches for the specified query in the first names, last names and usernames of the known user contacts @query Query to search for; can be empty to return all contacts @limit Maximum number of users to be returned searchContacts query:string limit:int32 = Users; -//@description Removes users from the contacts list @user_ids Identifiers of users to be deleted +//@description Removes users from the contact list @user_ids Identifiers of users to be deleted removeContacts user_ids:vector = Ok; //@description Returns the total number of imported contacts @@ -2938,7 +2973,7 @@ getImportedContactCount = Count; //-Query result depends on the result of the previous query, so only one query is possible at the same time @contacts The new list of contacts, contact's vCard are ignored and are not imported changeImportedContacts contacts:vector = ImportedContacts; -//@description Clears all imported contacts, contacts list remains unchanged +//@description Clears all imported contacts, contact list remains unchanged clearImportedContacts = Ok; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index ca3a51b0e..a5b619129 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 8b911c8dd..fd2776a4d 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -14696,7 +14696,7 @@ Result MessagesManager::send_message(DialogId dialog_id, MessageId re update_dialog_draft_message(d, nullptr, false, !need_update_dialog_pos); } - send_update_new_message(d, m, true); + send_update_new_message(d, m); if (need_update_dialog_pos) { send_update_chat_last_message(d, "send_message"); } @@ -14923,7 +14923,7 @@ Result> MessagesManager::send_message_group( save_send_message_logevent(dialog_id, m); do_send_message(dialog_id, m); - send_update_new_message(d, m, true); + send_update_new_message(d, m); } if (need_update_dialog_pos) { @@ -15482,7 +15482,7 @@ Result MessagesManager::send_bot_start_message(UserId bot_user_id, Di create_text_message_content(text, std::move(text_entities), WebPageId()), &need_update_dialog_pos); - send_update_new_message(d, m, true); + send_update_new_message(d, m); if (need_update_dialog_pos) { send_update_chat_last_message(d, "send_bot_start_message"); } @@ -15611,7 +15611,7 @@ Result MessagesManager::send_inline_query_result_message(DialogId dia update_dialog_draft_message(d, nullptr, false, !need_update_dialog_pos); - send_update_new_message(d, m, true); + send_update_new_message(d, m); if (need_update_dialog_pos) { send_update_chat_last_message(d, "send_inline_query_result_message"); } @@ -16980,7 +16980,7 @@ Result> MessagesManager::forward_messages(DialogId to_dialog_i forwarded_messages.push_back(m); forwarded_message_ids.push_back(message_id); - send_update_new_message(to_dialog, m, true); + send_update_new_message(to_dialog, m); } if (!forwarded_messages.empty()) { @@ -17000,7 +17000,7 @@ Result> MessagesManager::forward_messages(DialogId to_dialog_i do_send_message(to_dialog_id, m); result[i] = m->message_id; - send_update_new_message(to_dialog, m, true); + send_update_new_message(to_dialog, m); } } @@ -17032,7 +17032,7 @@ Result MessagesManager::send_dialog_set_ttl_message(DialogId dialog_i Message *m = get_message_to_send(d, MessageId(), false, false, create_chat_set_ttl_message_content(ttl), &need_update_dialog_pos); - send_update_new_message(d, m, true); + send_update_new_message(d, m); if (need_update_dialog_pos) { send_update_chat_last_message(d, "send_dialog_set_ttl_message"); } @@ -17067,7 +17067,7 @@ Status MessagesManager::send_screenshot_taken_notification_message(DialogId dial do_send_screenshot_taken_notification_message(dialog_id, m, 0); - send_update_new_message(d, m, true); + send_update_new_message(d, m); if (need_update_dialog_pos) { send_update_chat_last_message(d, "send_screenshot_taken_notification_message"); } @@ -17225,7 +17225,7 @@ Result MessagesManager::add_local_message( update_dialog_draft_message(d, nullptr, false, !need_update_dialog_pos); } - send_update_new_message(d, result, true); + send_update_new_message(d, result); if (need_update_dialog_pos) { send_update_chat_last_message(d, "add_local_message"); } @@ -17311,63 +17311,70 @@ void MessagesManager::on_dialog_updated(DialogId dialog_id, const char *source) } } -void MessagesManager::send_update_new_message(Dialog *d, const Message *m, bool force) { +void MessagesManager::send_update_new_message(Dialog *d, const Message *m) { CHECK(d != nullptr); CHECK(m != nullptr); - LOG(INFO) << "Trying to " << (force ? "forcely " : "") << "send updateNewMessage for " << m->message_id << " in " - << d->dialog_id; - bool disable_notification = - m->disable_notification || m->is_outgoing || d->dialog_id == get_my_dialog_id() || td_->auth_manager_->is_bot(); + LOG(INFO) << "Send updateNewMessage for " << m->message_id << " in " << d->dialog_id; + send_closure(G()->td(), &Td::send_update, + make_tl_object(get_message_object(d->dialog_id, m))); + + add_new_message_notification(d, m, false); +} + +void MessagesManager::add_new_message_notification(Dialog *d, const Message *m, bool force) { + CHECK(d != nullptr); + CHECK(m != nullptr); + + if (m->disable_notification || m->is_outgoing || d->dialog_id == get_my_dialog_id() || td_->auth_manager_->is_bot()) { + return; + } if (m->message_id.get() <= d->last_read_inbox_message_id.get()) { LOG(INFO) << "Disable notification for read " << m->message_id << " in " << d->dialog_id; - disable_notification = true; + return; } - if (!disable_notification && d->dialog_id.get_type() == DialogType::Channel) { - if (!td_->contacts_manager_->get_channel_status(d->dialog_id.get_channel_id()).is_member()) { - disable_notification = true; - } - } - bool have_settings = true; - DialogId settings_dialog_id; - Dialog *settings_dialog = nullptr; - if (!disable_notification) { - if (!m->contains_mention || !m->sender_user_id.is_valid()) { - // use notification settings from the dialog - settings_dialog_id = d->dialog_id; - settings_dialog = d; - } else { - // have a mention, so use notification settings from the dialog with the sender - settings_dialog_id = DialogId(m->sender_user_id); - settings_dialog = get_dialog_force(settings_dialog_id); - } - - int32 mute_until; - std::tie(have_settings, mute_until) = get_dialog_mute_until(settings_dialog_id, settings_dialog); - if (mute_until > G()->unix_time()) { - disable_notification = true; - } + if (d->dialog_id.get_type() == DialogType::Channel && + !td_->contacts_manager_->get_channel_status(d->dialog_id.get_channel_id()).is_member()) { + return; } - if (!force && (!have_settings || !d->pending_update_new_messages.empty())) { - LOG(INFO) << "Delay update new message for " << m->message_id << " in " << d->dialog_id << " with " - << d->pending_update_new_messages.size() << " already waiting messages"; - if (d->pending_update_new_messages.empty()) { + LOG(INFO) << "Trying to " << (force ? "forcely " : "") << "add new message notification for " << m->message_id + << " in " << d->dialog_id; + + DialogId settings_dialog_id = d->dialog_id; + Dialog *settings_dialog = d; + if (m->contains_mention && m->sender_user_id.is_valid()) { + // have a mention, so use notification settings from the dialog with the sender + settings_dialog_id = DialogId(m->sender_user_id); + settings_dialog = get_dialog_force(settings_dialog_id); + } + + bool have_settings; + int32 mute_until; + std::tie(have_settings, mute_until) = get_dialog_mute_until(settings_dialog_id, settings_dialog); + if (mute_until > G()->unix_time()) { + return; + } + + if (!force && (!have_settings || !d->pending_new_message_notifications.empty())) { + LOG(INFO) << "Delay new message notification for " << m->message_id << " in " << d->dialog_id << " with " + << d->pending_new_message_notifications.size() << " already waiting messages"; + if (d->pending_new_message_notifications.empty()) { create_actor( - "FlushPendingUpdateNewMessagesSleepActor", 5.0, + "FlushPendingNewMessageNotificationsSleepActor", 5.0, PromiseCreator::lambda([actor_id = actor_id(this), dialog_id = d->dialog_id](Result result) { - LOG(INFO) << "Flush pending updateNewMessages in " << dialog_id << " by timeout"; - send_closure(actor_id, &MessagesManager::flush_pending_update_new_messages, dialog_id); + LOG(INFO) << "Flush pending notifications in " << dialog_id << " by timeout"; + send_closure(actor_id, &MessagesManager::flush_pending_new_message_notifications, dialog_id); })) .release(); } - d->pending_update_new_messages.push_back(m->message_id); + d->pending_new_message_notifications.push_back(m->message_id); auto promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_id = d->dialog_id](Result result) { - LOG(INFO) << "Flush pending updateNewMessages in " << dialog_id << " because of received notification settings"; - send_closure(actor_id, &MessagesManager::flush_pending_update_new_messages, dialog_id); + LOG(INFO) << "Flush pending notifications in " << dialog_id << " because of received notification settings"; + send_closure(actor_id, &MessagesManager::flush_pending_new_message_notifications, dialog_id); }); if (settings_dialog == nullptr && have_input_peer(settings_dialog_id, AccessRights::Read)) { - force_create_dialog(settings_dialog_id, "send update new message"); + force_create_dialog(settings_dialog_id, "add_new_message_notification"); settings_dialog = get_dialog(settings_dialog_id); } if (settings_dialog != nullptr) { @@ -17379,25 +17386,23 @@ void MessagesManager::send_update_new_message(Dialog *d, const Message *m, bool } LOG_IF(WARNING, !have_settings) << "Have no notification settings for " << settings_dialog_id - << ", but forced to send updateNewMessage for " << m->message_id << " in " + << ", but forced to send notification about " << m->message_id << " in " << d->dialog_id; - send_closure(G()->td(), &Td::send_update, - make_tl_object(get_message_object(d->dialog_id, m), disable_notification, - m->contains_mention)); + // TODO } -void MessagesManager::flush_pending_update_new_messages(DialogId dialog_id) { +void MessagesManager::flush_pending_new_message_notifications(DialogId dialog_id) { auto d = get_dialog(dialog_id); CHECK(d != nullptr); - if (d->pending_update_new_messages.empty()) { + if (d->pending_new_message_notifications.empty()) { return; } - auto message_ids = std::move(d->pending_update_new_messages); - reset_to_empty(d->pending_update_new_messages); + auto message_ids = std::move(d->pending_new_message_notifications); + reset_to_empty(d->pending_new_message_notifications); for (auto message_id : message_ids) { auto m = get_message(d, message_id); if (m != nullptr) { - send_update_new_message(d, m, true); + add_new_message_notification(d, m, true); } } } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index f980f0270..6ff5b8e06 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -898,7 +898,7 @@ class MessagesManager : public Actor { std::unordered_set deleted_message_ids; - std::vector pending_update_new_messages; + std::vector pending_new_message_notifications; string client_data; @@ -1444,9 +1444,11 @@ class MessagesManager : public Actor { bool update_message_content(DialogId dialog_id, Message *old_message, unique_ptr new_content, bool need_send_update_message_content, bool need_merge_files); - void send_update_new_message(Dialog *d, const Message *m, bool force = false); + void send_update_new_message(Dialog *d, const Message *m); - void flush_pending_update_new_messages(DialogId dialog_id); + void add_new_message_notification(Dialog *d, const Message *m, bool force); + + void flush_pending_new_message_notifications(DialogId dialog_id); void send_update_message_send_succeeded(Dialog *d, MessageId old_message_id, const Message *m) const; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 867a45d44..4b9037f4a 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5060,6 +5060,18 @@ void Td::on_request(uint64 id, td_api::getChatMessageCount &request) { CREATE_REQUEST(GetChatMessageCountRequest, request.chat_id_, std::move(request.filter_), request.return_local_); } +void Td::on_request(uint64 id, const td_api::removeNotification &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + // TODO notification_manager->remove_notification(request.notification_id_, std::move(promise)); +} + +void Td::on_request(uint64 id, const td_api::removeNotifications &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + // TODO notification_manager->remove_notifications(request.notification_group_id_, request.max_notification_id_, std::move(promise)); +} + void Td::on_request(uint64 id, const td_api::deleteMessages &request) { CREATE_OK_REQUEST_PROMISE(); messages_manager_->delete_messages(DialogId(request.chat_id_), MessagesManager::get_message_ids(request.message_ids_), @@ -6202,6 +6214,14 @@ void Td::on_request(uint64 id, td_api::setOption &request) { return; } break; + case 'n': + if (!is_bot && set_integer_option("notification_group_count_max", 1, 25)) { + return; + } + if (!is_bot && set_integer_option("notification_group_size_max", 1, 25)) { + return; + } + break; case 'o': if (request.name_ == "online") { if (value_constructor_id != td_api::optionValueBoolean::ID && diff --git a/td/telegram/Td.h b/td/telegram/Td.h index d90a4dbaf..19ccdd59e 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -507,6 +507,10 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, td_api::getChatMessageCount &request); + void on_request(uint64 id, const td_api::removeNotification &request); + + void on_request(uint64 id, const td_api::removeNotifications &request); + void on_request(uint64 id, const td_api::deleteMessages &request); void on_request(uint64 id, const td_api::deleteChatMessagesFromUser &request);