1 //
2 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 #include "td/telegram/MessagesManager.h"
8 
9 #include "td/telegram/AuthManager.h"
10 #include "td/telegram/ChatId.h"
11 #include "td/telegram/ConfigShared.h"
12 #include "td/telegram/ContactsManager.h"
13 #include "td/telegram/Dependencies.h"
14 #include "td/telegram/DialogActionBar.h"
15 #include "td/telegram/DialogDb.h"
16 #include "td/telegram/DialogFilter.h"
17 #include "td/telegram/DialogFilter.hpp"
18 #include "td/telegram/DialogLocation.h"
19 #include "td/telegram/DraftMessage.h"
20 #include "td/telegram/DraftMessage.hpp"
21 #include "td/telegram/FileReferenceManager.h"
22 #include "td/telegram/files/FileId.hpp"
23 #include "td/telegram/files/FileLocation.h"
24 #include "td/telegram/files/FileManager.h"
25 #include "td/telegram/files/FileType.h"
26 #include "td/telegram/Global.h"
27 #include "td/telegram/GroupCallManager.h"
28 #include "td/telegram/InlineQueriesManager.h"
29 #include "td/telegram/InputMessageText.h"
30 #include "td/telegram/LinkManager.h"
31 #include "td/telegram/Location.h"
32 #include "td/telegram/logevent/LogEvent.h"
33 #include "td/telegram/MessageContent.h"
34 #include "td/telegram/MessageEntity.h"
35 #include "td/telegram/MessageEntity.hpp"
36 #include "td/telegram/MessagesDb.h"
37 #include "td/telegram/MessageSender.h"
38 #include "td/telegram/misc.h"
39 #include "td/telegram/net/DcId.h"
40 #include "td/telegram/net/NetActor.h"
41 #include "td/telegram/net/NetQuery.h"
42 #include "td/telegram/NotificationGroupType.h"
43 #include "td/telegram/NotificationManager.h"
44 #include "td/telegram/NotificationSettings.hpp"
45 #include "td/telegram/NotificationType.h"
46 #include "td/telegram/ReplyMarkup.h"
47 #include "td/telegram/ReplyMarkup.hpp"
48 #include "td/telegram/SecretChatsManager.h"
49 #include "td/telegram/SequenceDispatcher.h"
50 #include "td/telegram/Td.h"
51 #include "td/telegram/TdDb.h"
52 #include "td/telegram/TdParameters.h"
53 #include "td/telegram/TopDialogCategory.h"
54 #include "td/telegram/UpdatesManager.h"
55 #include "td/telegram/Version.h"
56 #include "td/telegram/WebPageId.h"
57 
58 #include "td/db/binlog/BinlogEvent.h"
59 #include "td/db/binlog/BinlogHelper.h"
60 #include "td/db/SqliteKeyValue.h"
61 #include "td/db/SqliteKeyValueAsync.h"
62 
63 #include "td/actor/PromiseFuture.h"
64 #include "td/actor/SleepActor.h"
65 
66 #include "td/utils/algorithm.h"
67 #include "td/utils/format.h"
68 #include "td/utils/misc.h"
69 #include "td/utils/PathView.h"
70 #include "td/utils/Random.h"
71 #include "td/utils/Slice.h"
72 #include "td/utils/SliceBuilder.h"
73 #include "td/utils/Time.h"
74 #include "td/utils/tl_helpers.h"
75 #include "td/utils/utf8.h"
76 
77 #include <algorithm>
78 #include <cstring>
79 #include <limits>
80 #include <tuple>
81 #include <type_traits>
82 #include <unordered_map>
83 #include <unordered_set>
84 #include <utility>
85 
86 namespace td {
87 
88 class GetDialogFiltersQuery final : public Td::ResultHandler {
89   Promise<vector<tl_object_ptr<telegram_api::dialogFilter>>> promise_;
90 
91  public:
GetDialogFiltersQuery(Promise<vector<tl_object_ptr<telegram_api::dialogFilter>>> && promise)92   explicit GetDialogFiltersQuery(Promise<vector<tl_object_ptr<telegram_api::dialogFilter>>> &&promise)
93       : promise_(std::move(promise)) {
94   }
95 
send()96   void send() {
97     send_query(G()->net_query_creator().create(telegram_api::messages_getDialogFilters()));
98   }
99 
on_result(BufferSlice packet)100   void on_result(BufferSlice packet) final {
101     auto result_ptr = fetch_result<telegram_api::messages_getDialogFilters>(packet);
102     if (result_ptr.is_error()) {
103       return on_error(result_ptr.move_as_error());
104     }
105 
106     promise_.set_value(result_ptr.move_as_ok());
107   }
108 
on_error(Status status)109   void on_error(Status status) final {
110     promise_.set_error(std::move(status));
111   }
112 };
113 
114 class UpdateDialogFilterQuery final : public Td::ResultHandler {
115   Promise<Unit> promise_;
116 
117  public:
UpdateDialogFilterQuery(Promise<Unit> && promise)118   explicit UpdateDialogFilterQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
119   }
120 
send(DialogFilterId dialog_filter_id,tl_object_ptr<telegram_api::dialogFilter> filter)121   void send(DialogFilterId dialog_filter_id, tl_object_ptr<telegram_api::dialogFilter> filter) {
122     int32 flags = 0;
123     if (filter != nullptr) {
124       flags |= telegram_api::messages_updateDialogFilter::FILTER_MASK;
125     }
126     send_query(G()->net_query_creator().create(
127         telegram_api::messages_updateDialogFilter(flags, dialog_filter_id.get(), std::move(filter))));
128   }
129 
on_result(BufferSlice packet)130   void on_result(BufferSlice packet) final {
131     auto result_ptr = fetch_result<telegram_api::messages_updateDialogFilter>(packet);
132     if (result_ptr.is_error()) {
133       return on_error(result_ptr.move_as_error());
134     }
135 
136     LOG(INFO) << "Receive result for UpdateDialogFilterQuery: " << result_ptr.ok();
137     promise_.set_value(Unit());
138   }
139 
on_error(Status status)140   void on_error(Status status) final {
141     LOG(ERROR) << "Receive error for UpdateDialogFilterQuery: " << status;
142     promise_.set_error(std::move(status));
143   }
144 };
145 
146 class UpdateDialogFiltersOrderQuery final : public Td::ResultHandler {
147   Promise<Unit> promise_;
148 
149  public:
UpdateDialogFiltersOrderQuery(Promise<Unit> && promise)150   explicit UpdateDialogFiltersOrderQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
151   }
152 
send(const vector<DialogFilterId> & dialog_filter_ids)153   void send(const vector<DialogFilterId> &dialog_filter_ids) {
154     send_query(G()->net_query_creator().create(telegram_api::messages_updateDialogFiltersOrder(
155         transform(dialog_filter_ids, [](auto dialog_filter_id) { return dialog_filter_id.get(); }))));
156   }
157 
on_result(BufferSlice packet)158   void on_result(BufferSlice packet) final {
159     auto result_ptr = fetch_result<telegram_api::messages_updateDialogFiltersOrder>(packet);
160     if (result_ptr.is_error()) {
161       return on_error(result_ptr.move_as_error());
162     }
163 
164     LOG(INFO) << "Receive result for UpdateDialogFiltersOrderQuery: " << result_ptr.ok();
165     promise_.set_value(Unit());
166   }
167 
on_error(Status status)168   void on_error(Status status) final {
169     promise_.set_error(std::move(status));
170   }
171 };
172 
173 class GetSuggestedDialogFiltersQuery final : public Td::ResultHandler {
174   Promise<vector<tl_object_ptr<telegram_api::dialogFilterSuggested>>> promise_;
175 
176  public:
GetSuggestedDialogFiltersQuery(Promise<vector<tl_object_ptr<telegram_api::dialogFilterSuggested>>> && promise)177   explicit GetSuggestedDialogFiltersQuery(Promise<vector<tl_object_ptr<telegram_api::dialogFilterSuggested>>> &&promise)
178       : promise_(std::move(promise)) {
179   }
180 
send()181   void send() {
182     send_query(G()->net_query_creator().create(telegram_api::messages_getSuggestedDialogFilters()));
183   }
184 
on_result(BufferSlice packet)185   void on_result(BufferSlice packet) final {
186     auto result_ptr = fetch_result<telegram_api::messages_getSuggestedDialogFilters>(packet);
187     if (result_ptr.is_error()) {
188       return on_error(result_ptr.move_as_error());
189     }
190 
191     promise_.set_value(result_ptr.move_as_ok());
192   }
193 
on_error(Status status)194   void on_error(Status status) final {
195     promise_.set_error(std::move(status));
196   }
197 };
198 
199 class GetOnlinesQuery final : public Td::ResultHandler {
200   DialogId dialog_id_;
201 
202  public:
send(DialogId dialog_id)203   void send(DialogId dialog_id) {
204     dialog_id_ = dialog_id;
205     CHECK(dialog_id.get_type() == DialogType::Channel);
206     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
207     if (input_peer == nullptr) {
208       return on_error(Status::Error(400, "Can't access the chat"));
209     }
210 
211     send_query(G()->net_query_creator().create(telegram_api::messages_getOnlines(std::move(input_peer))));
212   }
213 
on_result(BufferSlice packet)214   void on_result(BufferSlice packet) final {
215     auto result_ptr = fetch_result<telegram_api::messages_getOnlines>(packet);
216     if (result_ptr.is_error()) {
217       return on_error(result_ptr.move_as_error());
218     }
219 
220     auto result = result_ptr.move_as_ok();
221     td_->messages_manager_->on_update_dialog_online_member_count(dialog_id_, result->onlines_, true);
222   }
223 
on_error(Status status)224   void on_error(Status status) final {
225     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetOnlinesQuery");
226     td_->messages_manager_->on_update_dialog_online_member_count(dialog_id_, 0, true);
227   }
228 };
229 
230 class GetAllDraftsQuery final : public Td::ResultHandler {
231  public:
send()232   void send() {
233     send_query(G()->net_query_creator().create(telegram_api::messages_getAllDrafts()));
234   }
235 
on_result(BufferSlice packet)236   void on_result(BufferSlice packet) final {
237     auto result_ptr = fetch_result<telegram_api::messages_getAllDrafts>(packet);
238     if (result_ptr.is_error()) {
239       return on_error(result_ptr.move_as_error());
240     }
241 
242     auto ptr = result_ptr.move_as_ok();
243     LOG(INFO) << "Receive result for GetAllDraftsQuery: " << to_string(ptr);
244     td_->updates_manager_->on_get_updates(std::move(ptr), Promise<Unit>());
245   }
246 
on_error(Status status)247   void on_error(Status status) final {
248     if (!G()->is_expected_error(status)) {
249       LOG(ERROR) << "Receive error for GetAllDraftsQuery: " << status;
250     }
251     status.ignore();
252   }
253 };
254 
255 class GetDialogQuery final : public Td::ResultHandler {
256   DialogId dialog_id_;
257 
258  public:
send(DialogId dialog_id)259   void send(DialogId dialog_id) {
260     dialog_id_ = dialog_id;
261     send_query(G()->net_query_creator().create(telegram_api::messages_getPeerDialogs(
262         td_->messages_manager_->get_input_dialog_peers({dialog_id}, AccessRights::Read))));
263   }
264 
on_result(BufferSlice packet)265   void on_result(BufferSlice packet) final {
266     auto result_ptr = fetch_result<telegram_api::messages_getPeerDialogs>(packet);
267     if (result_ptr.is_error()) {
268       return on_error(result_ptr.move_as_error());
269     }
270 
271     auto result = result_ptr.move_as_ok();
272     LOG(INFO) << "Receive result for GetDialogQuery: " << to_string(result);
273 
274     td_->contacts_manager_->on_get_users(std::move(result->users_), "GetDialogQuery");
275     td_->contacts_manager_->on_get_chats(std::move(result->chats_), "GetDialogQuery");
276     td_->messages_manager_->on_get_dialogs(FolderId(), std::move(result->dialogs_), -1, std::move(result->messages_),
277                                            PromiseCreator::lambda([actor_id = td_->messages_manager_actor_.get(),
278                                                                    dialog_id = dialog_id_](Result<> result) {
279                                              send_closure(actor_id, &MessagesManager::on_get_dialog_query_finished,
280                                                           dialog_id,
281                                                           result.is_error() ? result.move_as_error() : Status::OK());
282                                            }));
283   }
284 
on_error(Status status)285   void on_error(Status status) final {
286     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetDialogQuery");
287     td_->messages_manager_->on_get_dialog_query_finished(dialog_id_, std::move(status));
288   }
289 };
290 
291 class GetDialogsQuery final : public Td::ResultHandler {
292   Promise<Unit> promise_;
293 
294  public:
GetDialogsQuery(Promise<Unit> && promise)295   explicit GetDialogsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
296   }
297 
send(vector<InputDialogId> input_dialog_ids)298   void send(vector<InputDialogId> input_dialog_ids) {
299     CHECK(!input_dialog_ids.empty());
300     CHECK(input_dialog_ids.size() <= 100);
301     auto input_dialog_peers = InputDialogId::get_input_dialog_peers(input_dialog_ids);
302     CHECK(input_dialog_peers.size() == input_dialog_ids.size());
303     send_query(G()->net_query_creator().create(telegram_api::messages_getPeerDialogs(std::move(input_dialog_peers))));
304   }
305 
on_result(BufferSlice packet)306   void on_result(BufferSlice packet) final {
307     auto result_ptr = fetch_result<telegram_api::messages_getPeerDialogs>(packet);
308     if (result_ptr.is_error()) {
309       return on_error(result_ptr.move_as_error());
310     }
311 
312     auto result = result_ptr.move_as_ok();
313     LOG(INFO) << "Receive result for GetDialogsQuery: " << to_string(result);
314 
315     td_->contacts_manager_->on_get_users(std::move(result->users_), "GetDialogsQuery");
316     td_->contacts_manager_->on_get_chats(std::move(result->chats_), "GetDialogsQuery");
317     td_->messages_manager_->on_get_dialogs(FolderId(), std::move(result->dialogs_), -1, std::move(result->messages_),
318                                            std::move(promise_));
319   }
320 
on_error(Status status)321   void on_error(Status status) final {
322     promise_.set_error(std::move(status));
323   }
324 };
325 
326 class GetPinnedDialogsActor final : public NetActorOnce {
327   FolderId folder_id_;
328   Promise<Unit> promise_;
329 
330  public:
GetPinnedDialogsActor(Promise<Unit> && promise)331   explicit GetPinnedDialogsActor(Promise<Unit> &&promise) : promise_(std::move(promise)) {
332   }
333 
send(FolderId folder_id,uint64 sequence_id)334   NetQueryRef send(FolderId folder_id, uint64 sequence_id) {
335     folder_id_ = folder_id;
336     auto query = G()->net_query_creator().create(telegram_api::messages_getPinnedDialogs(folder_id.get()));
337     auto result = query.get_weak();
338     send_closure(td_->messages_manager_->sequence_dispatcher_, &MultiSequenceDispatcher::send_with_callback,
339                  std::move(query), actor_shared(this), sequence_id);
340     return result;
341   }
342 
on_result(BufferSlice packet)343   void on_result(BufferSlice packet) final {
344     auto result_ptr = fetch_result<telegram_api::messages_getPinnedDialogs>(packet);
345     if (result_ptr.is_error()) {
346       return on_error(result_ptr.move_as_error());
347     }
348 
349     auto result = result_ptr.move_as_ok();
350     LOG(INFO) << "Receive pinned chats in " << folder_id_ << ": " << to_string(result);
351 
352     td_->contacts_manager_->on_get_users(std::move(result->users_), "GetPinnedDialogsActor");
353     td_->contacts_manager_->on_get_chats(std::move(result->chats_), "GetPinnedDialogsActor");
354     td_->messages_manager_->on_get_dialogs(folder_id_, std::move(result->dialogs_), -2, std::move(result->messages_),
355                                            std::move(promise_));
356   }
357 
on_error(Status status)358   void on_error(Status status) final {
359     promise_.set_error(std::move(status));
360   }
361 };
362 
363 class GetDialogUnreadMarksQuery final : public Td::ResultHandler {
364  public:
send()365   void send() {
366     send_query(G()->net_query_creator().create(telegram_api::messages_getDialogUnreadMarks()));
367   }
368 
on_result(BufferSlice packet)369   void on_result(BufferSlice packet) final {
370     auto result_ptr = fetch_result<telegram_api::messages_getDialogUnreadMarks>(packet);
371     if (result_ptr.is_error()) {
372       return on_error(result_ptr.move_as_error());
373     }
374 
375     auto results = result_ptr.move_as_ok();
376     for (auto &result : results) {
377       td_->messages_manager_->on_update_dialog_is_marked_as_unread(DialogId(result), true);
378     }
379 
380     G()->td_db()->get_binlog_pmc()->set("fetched_marks_as_unread", "1");
381   }
382 
on_error(Status status)383   void on_error(Status status) final {
384     if (!G()->is_expected_error(status)) {
385       LOG(ERROR) << "Receive error for GetDialogUnreadMarksQuery: " << status;
386     }
387     status.ignore();
388   }
389 };
390 
391 class GetDiscussionMessageQuery final : public Td::ResultHandler {
392   Promise<MessageThreadInfo> promise_;
393   DialogId dialog_id_;
394   MessageId message_id_;
395   DialogId expected_dialog_id_;
396   MessageId expected_message_id_;
397 
398  public:
GetDiscussionMessageQuery(Promise<MessageThreadInfo> && promise)399   explicit GetDiscussionMessageQuery(Promise<MessageThreadInfo> &&promise) : promise_(std::move(promise)) {
400   }
401 
send(DialogId dialog_id,MessageId message_id,DialogId expected_dialog_id,MessageId expected_message_id)402   void send(DialogId dialog_id, MessageId message_id, DialogId expected_dialog_id, MessageId expected_message_id) {
403     dialog_id_ = dialog_id;
404     message_id_ = message_id;
405     expected_dialog_id_ = expected_dialog_id;
406     expected_message_id_ = expected_message_id;
407     CHECK(expected_dialog_id_.is_valid());
408     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
409     CHECK(input_peer != nullptr);
410     send_query(G()->net_query_creator().create(
411         telegram_api::messages_getDiscussionMessage(std::move(input_peer), message_id.get_server_message_id().get())));
412   }
413 
on_result(BufferSlice packet)414   void on_result(BufferSlice packet) final {
415     auto result_ptr = fetch_result<telegram_api::messages_getDiscussionMessage>(packet);
416     if (result_ptr.is_error()) {
417       return on_error(result_ptr.move_as_error());
418     }
419 
420     td_->messages_manager_->process_discussion_message(result_ptr.move_as_ok(), dialog_id_, message_id_,
421                                                        expected_dialog_id_, expected_message_id_, std::move(promise_));
422   }
423 
on_error(Status status)424   void on_error(Status status) final {
425     if (expected_dialog_id_ == dialog_id_) {
426       td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetDiscussionMessageQuery");
427     }
428     promise_.set_error(std::move(status));
429   }
430 };
431 
432 class GetMessagesQuery final : public Td::ResultHandler {
433   Promise<Unit> promise_;
434 
435  public:
GetMessagesQuery(Promise<Unit> && promise)436   explicit GetMessagesQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
437   }
438 
send(vector<tl_object_ptr<telegram_api::InputMessage>> && message_ids)439   void send(vector<tl_object_ptr<telegram_api::InputMessage>> &&message_ids) {
440     send_query(G()->net_query_creator().create(telegram_api::messages_getMessages(std::move(message_ids))));
441   }
442 
on_result(BufferSlice packet)443   void on_result(BufferSlice packet) final {
444     auto result_ptr = fetch_result<telegram_api::messages_getMessages>(packet);
445     if (result_ptr.is_error()) {
446       return on_error(result_ptr.move_as_error());
447     }
448 
449     auto info = td_->messages_manager_->get_messages_info(result_ptr.move_as_ok(), "GetMessagesQuery");
450     LOG_IF(ERROR, info.is_channel_messages) << "Receive channel messages in GetMessagesQuery";
451     td_->messages_manager_->on_get_messages(std::move(info.messages), info.is_channel_messages, false,
452                                             std::move(promise_), "GetMessagesQuery");
453   }
454 
on_error(Status status)455   void on_error(Status status) final {
456     if (status.message() == "MESSAGE_IDS_EMPTY") {
457       promise_.set_value(Unit());
458       return;
459     }
460     promise_.set_error(std::move(status));
461   }
462 };
463 
464 class GetChannelMessagesQuery final : public Td::ResultHandler {
465   Promise<Unit> promise_;
466   ChannelId channel_id_;
467   MessageId last_new_message_id_;
468 
469  public:
GetChannelMessagesQuery(Promise<Unit> && promise)470   explicit GetChannelMessagesQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
471   }
472 
send(ChannelId channel_id,tl_object_ptr<telegram_api::InputChannel> && input_channel,vector<tl_object_ptr<telegram_api::InputMessage>> && message_ids,MessageId last_new_message_id)473   void send(ChannelId channel_id, tl_object_ptr<telegram_api::InputChannel> &&input_channel,
474             vector<tl_object_ptr<telegram_api::InputMessage>> &&message_ids, MessageId last_new_message_id) {
475     channel_id_ = channel_id;
476     last_new_message_id_ = last_new_message_id;
477     CHECK(input_channel != nullptr);
478     send_query(G()->net_query_creator().create(
479         telegram_api::channels_getMessages(std::move(input_channel), std::move(message_ids))));
480   }
481 
on_result(BufferSlice packet)482   void on_result(BufferSlice packet) final {
483     auto result_ptr = fetch_result<telegram_api::channels_getMessages>(packet);
484     if (result_ptr.is_error()) {
485       return on_error(result_ptr.move_as_error());
486     }
487 
488     auto info = td_->messages_manager_->get_messages_info(result_ptr.move_as_ok(), "GetChannelMessagesQuery");
489     LOG_IF(ERROR, !info.is_channel_messages) << "Receive ordinary messages in GetChannelMessagesQuery";
490     // messages with invalid big identifiers can be received as messageEmpty
491     // bots can receive messageEmpty because of their privacy mode
492     if (last_new_message_id_.is_valid() && !td_->auth_manager_->is_bot()) {
493       vector<MessageId> empty_message_ids;
494       for (auto &message : info.messages) {
495         if (message->get_id() == telegram_api::messageEmpty::ID) {
496           auto message_id = MessagesManager::get_message_id(message, false);
497           if (message_id.is_valid() && message_id <= last_new_message_id_) {
498             empty_message_ids.push_back(message_id);
499           }
500         }
501       }
502       td_->messages_manager_->on_get_empty_messages(DialogId(channel_id_), empty_message_ids);
503     }
504     td_->messages_manager_->get_channel_difference_if_needed(
505         DialogId(channel_id_), std::move(info),
506         PromiseCreator::lambda([actor_id = td_->messages_manager_actor_.get(),
507                                 promise = std::move(promise_)](Result<MessagesManager::MessagesInfo> &&result) mutable {
508           if (result.is_error()) {
509             promise.set_error(result.move_as_error());
510           } else {
511             auto info = result.move_as_ok();
512             send_closure(actor_id, &MessagesManager::on_get_messages, std::move(info.messages),
513                          info.is_channel_messages, false, std::move(promise), "GetChannelMessagesQuery");
514           }
515         }));
516   }
517 
on_error(Status status)518   void on_error(Status status) final {
519     if (status.message() == "MESSAGE_IDS_EMPTY") {
520       promise_.set_value(Unit());
521       return;
522     }
523     td_->contacts_manager_->on_get_channel_error(channel_id_, status, "GetChannelMessagesQuery");
524     promise_.set_error(std::move(status));
525   }
526 };
527 
528 class GetScheduledMessagesQuery final : public Td::ResultHandler {
529   Promise<Unit> promise_;
530   DialogId dialog_id_;
531 
532  public:
GetScheduledMessagesQuery(Promise<Unit> && promise)533   explicit GetScheduledMessagesQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
534   }
535 
send(DialogId dialog_id,tl_object_ptr<telegram_api::InputPeer> && input_peer,vector<int32> && message_ids)536   void send(DialogId dialog_id, tl_object_ptr<telegram_api::InputPeer> &&input_peer, vector<int32> &&message_ids) {
537     dialog_id_ = dialog_id;
538     CHECK(input_peer != nullptr);
539     send_query(G()->net_query_creator().create(
540         telegram_api::messages_getScheduledMessages(std::move(input_peer), std::move(message_ids))));
541   }
542 
on_result(BufferSlice packet)543   void on_result(BufferSlice packet) final {
544     auto result_ptr = fetch_result<telegram_api::messages_getScheduledMessages>(packet);
545     if (result_ptr.is_error()) {
546       return on_error(result_ptr.move_as_error());
547     }
548 
549     auto info = td_->messages_manager_->get_messages_info(result_ptr.move_as_ok(), "GetScheduledMessagesQuery");
550     LOG_IF(ERROR, info.is_channel_messages != (dialog_id_.get_type() == DialogType::Channel))
551         << "Receive wrong messages constructor in GetScheduledMessagesQuery";
552     td_->messages_manager_->on_get_messages(std::move(info.messages), info.is_channel_messages, true,
553                                             std::move(promise_), "GetScheduledMessagesQuery");
554   }
555 
on_error(Status status)556   void on_error(Status status) final {
557     if (status.message() == "MESSAGE_IDS_EMPTY") {
558       promise_.set_value(Unit());
559       return;
560     }
561     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetScheduledMessagesQuery");
562     promise_.set_error(std::move(status));
563   }
564 };
565 
566 class UpdateDialogPinnedMessageQuery final : public Td::ResultHandler {
567   Promise<Unit> promise_;
568   DialogId dialog_id_;
569 
570  public:
UpdateDialogPinnedMessageQuery(Promise<Unit> && promise)571   explicit UpdateDialogPinnedMessageQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
572   }
573 
send(DialogId dialog_id,MessageId message_id,bool is_unpin,bool disable_notification,bool only_for_self)574   void send(DialogId dialog_id, MessageId message_id, bool is_unpin, bool disable_notification, bool only_for_self) {
575     dialog_id_ = dialog_id;
576     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
577     if (input_peer == nullptr) {
578       LOG(INFO) << "Can't update pinned message in " << dialog_id;
579       return on_error(Status::Error(400, "Can't update pinned message"));
580     }
581 
582     int32 flags = 0;
583     if (disable_notification) {
584       flags |= telegram_api::messages_updatePinnedMessage::SILENT_MASK;
585     }
586     if (is_unpin) {
587       flags |= telegram_api::messages_updatePinnedMessage::UNPIN_MASK;
588     }
589     if (only_for_self) {
590       flags |= telegram_api::messages_updatePinnedMessage::PM_ONESIDE_MASK;
591     }
592     send_query(G()->net_query_creator().create(
593         telegram_api::messages_updatePinnedMessage(flags, false /*ignored*/, false /*ignored*/, false /*ignored*/,
594                                                    std::move(input_peer), message_id.get_server_message_id().get())));
595   }
596 
on_result(BufferSlice packet)597   void on_result(BufferSlice packet) final {
598     auto result_ptr = fetch_result<telegram_api::messages_updatePinnedMessage>(packet);
599     if (result_ptr.is_error()) {
600       return on_error(result_ptr.move_as_error());
601     }
602 
603     auto ptr = result_ptr.move_as_ok();
604     LOG(INFO) << "Receive result for UpdateDialogPinnedMessageQuery: " << to_string(ptr);
605     td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
606   }
607 
on_error(Status status)608   void on_error(Status status) final {
609     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "UpdateDialogPinnedMessageQuery");
610     promise_.set_error(std::move(status));
611   }
612 };
613 
614 class UnpinAllMessagesQuery final : public Td::ResultHandler {
615   Promise<AffectedHistory> promise_;
616   DialogId dialog_id_;
617 
618  public:
UnpinAllMessagesQuery(Promise<AffectedHistory> && promise)619   explicit UnpinAllMessagesQuery(Promise<AffectedHistory> &&promise) : promise_(std::move(promise)) {
620   }
621 
send(DialogId dialog_id)622   void send(DialogId dialog_id) {
623     dialog_id_ = dialog_id;
624 
625     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id_, AccessRights::Write);
626     if (input_peer == nullptr) {
627       LOG(INFO) << "Can't unpin all messages in " << dialog_id_;
628       return on_error(Status::Error(400, "Can't unpin all messages"));
629     }
630 
631     send_query(G()->net_query_creator().create(telegram_api::messages_unpinAllMessages(std::move(input_peer))));
632   }
633 
on_result(BufferSlice packet)634   void on_result(BufferSlice packet) final {
635     auto result_ptr = fetch_result<telegram_api::messages_unpinAllMessages>(packet);
636     if (result_ptr.is_error()) {
637       return on_error(result_ptr.move_as_error());
638     }
639 
640     promise_.set_value(AffectedHistory(result_ptr.move_as_ok()));
641   }
642 
on_error(Status status)643   void on_error(Status status) final {
644     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "UnpinAllMessagesQuery");
645     promise_.set_error(std::move(status));
646   }
647 };
648 
649 class GetMessageReadParticipantsQuery final : public Td::ResultHandler {
650   Promise<vector<UserId>> promise_;
651   DialogId dialog_id_;
652 
653  public:
GetMessageReadParticipantsQuery(Promise<vector<UserId>> && promise)654   explicit GetMessageReadParticipantsQuery(Promise<vector<UserId>> &&promise) : promise_(std::move(promise)) {
655   }
656 
send(DialogId dialog_id,MessageId message_id)657   void send(DialogId dialog_id, MessageId message_id) {
658     dialog_id_ = dialog_id;
659     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
660     CHECK(input_peer != nullptr);
661     send_query(G()->net_query_creator().create(telegram_api::messages_getMessageReadParticipants(
662         std::move(input_peer), message_id.get_server_message_id().get())));
663   }
664 
on_result(BufferSlice packet)665   void on_result(BufferSlice packet) final {
666     auto result_ptr = fetch_result<telegram_api::messages_getMessageReadParticipants>(packet);
667     if (result_ptr.is_error()) {
668       return on_error(result_ptr.move_as_error());
669     }
670 
671     promise_.set_value(UserId::get_user_ids(result_ptr.ok()));
672   }
673 
on_error(Status status)674   void on_error(Status status) final {
675     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetMessageReadParticipantsQuery");
676     promise_.set_error(std::move(status));
677   }
678 };
679 
680 class ExportChannelMessageLinkQuery final : public Td::ResultHandler {
681   Promise<Unit> promise_;
682   ChannelId channel_id_;
683   MessageId message_id_;
684   bool for_group_ = false;
685   bool ignore_result_ = false;
686 
687  public:
ExportChannelMessageLinkQuery(Promise<Unit> && promise)688   explicit ExportChannelMessageLinkQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
689   }
690 
send(ChannelId channel_id,MessageId message_id,bool for_group,bool ignore_result)691   void send(ChannelId channel_id, MessageId message_id, bool for_group, bool ignore_result) {
692     channel_id_ = channel_id;
693     message_id_ = message_id;
694     for_group_ = for_group;
695     ignore_result_ = ignore_result;
696     auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
697     if (input_channel == nullptr) {
698       return on_error(Status::Error(400, "Can't access the chat"));
699     }
700     int32 flags = 0;
701     if (for_group) {
702       flags |= telegram_api::channels_exportMessageLink::GROUPED_MASK;
703     }
704     send_query(G()->net_query_creator().create(
705         telegram_api::channels_exportMessageLink(flags, false /*ignored*/, false /*ignored*/, std::move(input_channel),
706                                                  message_id.get_server_message_id().get())));
707   }
708 
on_result(BufferSlice packet)709   void on_result(BufferSlice packet) final {
710     auto result_ptr = fetch_result<telegram_api::channels_exportMessageLink>(packet);
711     if (result_ptr.is_error()) {
712       return on_error(result_ptr.move_as_error());
713     }
714 
715     auto ptr = result_ptr.move_as_ok();
716     LOG(DEBUG) << "Receive result for ExportChannelMessageLinkQuery: " << to_string(ptr);
717     if (!ignore_result_) {
718       td_->messages_manager_->on_get_public_message_link({DialogId(channel_id_), message_id_}, for_group_,
719                                                          std::move(ptr->link_), std::move(ptr->html_));
720     }
721 
722     promise_.set_value(Unit());
723   }
724 
on_error(Status status)725   void on_error(Status status) final {
726     if (!ignore_result_) {
727       td_->contacts_manager_->on_get_channel_error(channel_id_, status, "ExportChannelMessageLinkQuery");
728     }
729     promise_.set_error(std::move(status));
730   }
731 };
732 
733 class GetDialogListActor final : public NetActorOnce {
734   FolderId folder_id_;
735   Promise<Unit> promise_;
736 
737  public:
GetDialogListActor(Promise<Unit> && promise)738   explicit GetDialogListActor(Promise<Unit> &&promise) : promise_(std::move(promise)) {
739   }
740 
send(FolderId folder_id,int32 offset_date,ServerMessageId offset_message_id,DialogId offset_dialog_id,int32 limit,uint64 sequence_id)741   void send(FolderId folder_id, int32 offset_date, ServerMessageId offset_message_id, DialogId offset_dialog_id,
742             int32 limit, uint64 sequence_id) {
743     folder_id_ = folder_id;
744     auto input_peer = MessagesManager::get_input_peer_force(offset_dialog_id);
745     CHECK(input_peer != nullptr);
746 
747     int32 flags =
748         telegram_api::messages_getDialogs::EXCLUDE_PINNED_MASK | telegram_api::messages_getDialogs::FOLDER_ID_MASK;
749     auto query = G()->net_query_creator().create(
750         telegram_api::messages_getDialogs(flags, false /*ignored*/, folder_id.get(), offset_date,
751                                           offset_message_id.get(), std::move(input_peer), limit, 0));
752     send_closure(td_->messages_manager_->sequence_dispatcher_, &MultiSequenceDispatcher::send_with_callback,
753                  std::move(query), actor_shared(this), sequence_id);
754   }
755 
on_result(BufferSlice packet)756   void on_result(BufferSlice packet) final {
757     auto result_ptr = fetch_result<telegram_api::messages_getDialogs>(packet);
758     if (result_ptr.is_error()) {
759       return on_error(result_ptr.move_as_error());
760     }
761 
762     auto ptr = result_ptr.move_as_ok();
763     LOG(INFO) << "Receive chats from chat list of " << folder_id_ << ": " << to_string(ptr);
764     switch (ptr->get_id()) {
765       case telegram_api::messages_dialogs::ID: {
766         auto dialogs = move_tl_object_as<telegram_api::messages_dialogs>(ptr);
767         td_->contacts_manager_->on_get_users(std::move(dialogs->users_), "GetDialogListActor");
768         td_->contacts_manager_->on_get_chats(std::move(dialogs->chats_), "GetDialogListActor");
769         td_->messages_manager_->on_get_dialogs(folder_id_, std::move(dialogs->dialogs_),
770                                                narrow_cast<int32>(dialogs->dialogs_.size()),
771                                                std::move(dialogs->messages_), std::move(promise_));
772         break;
773       }
774       case telegram_api::messages_dialogsSlice::ID: {
775         auto dialogs = move_tl_object_as<telegram_api::messages_dialogsSlice>(ptr);
776         td_->contacts_manager_->on_get_users(std::move(dialogs->users_), "GetDialogListActor");
777         td_->contacts_manager_->on_get_chats(std::move(dialogs->chats_), "GetDialogListActor");
778         td_->messages_manager_->on_get_dialogs(folder_id_, std::move(dialogs->dialogs_), max(dialogs->count_, 0),
779                                                std::move(dialogs->messages_), std::move(promise_));
780         break;
781       }
782       case telegram_api::messages_dialogsNotModified::ID:
783         LOG(ERROR) << "Receive " << to_string(ptr);
784         return on_error(Status::Error(500, "Receive wrong server response messages.dialogsNotModified"));
785       default:
786         UNREACHABLE();
787     }
788   }
789 
on_error(Status status)790   void on_error(Status status) final {
791     promise_.set_error(std::move(status));
792   }
793 };
794 
795 class SearchPublicDialogsQuery final : public Td::ResultHandler {
796   string query_;
797 
798  public:
send(const string & query)799   void send(const string &query) {
800     query_ = query;
801     send_query(G()->net_query_creator().create(telegram_api::contacts_search(query, 3 /* ignored server-side */)));
802   }
803 
on_result(BufferSlice packet)804   void on_result(BufferSlice packet) final {
805     auto result_ptr = fetch_result<telegram_api::contacts_search>(packet);
806     if (result_ptr.is_error()) {
807       return on_error(result_ptr.move_as_error());
808     }
809 
810     auto dialogs = result_ptr.move_as_ok();
811     LOG(INFO) << "Receive result for SearchPublicDialogsQuery: " << to_string(dialogs);
812     td_->contacts_manager_->on_get_users(std::move(dialogs->users_), "SearchPublicDialogsQuery");
813     td_->contacts_manager_->on_get_chats(std::move(dialogs->chats_), "SearchPublicDialogsQuery");
814     td_->messages_manager_->on_get_public_dialogs_search_result(query_, std::move(dialogs->my_results_),
815                                                                 std::move(dialogs->results_));
816   }
817 
on_error(Status status)818   void on_error(Status status) final {
819     if (!G()->is_expected_error(status)) {
820       LOG(ERROR) << "Receive error for SearchPublicDialogsQuery: " << status;
821     }
822     td_->messages_manager_->on_failed_public_dialogs_search(query_, std::move(status));
823   }
824 };
825 
826 class GetCommonDialogsQuery final : public Td::ResultHandler {
827   Promise<Unit> promise_;
828   UserId user_id_;
829   int64 offset_chat_id_ = 0;
830 
831  public:
GetCommonDialogsQuery(Promise<Unit> && promise)832   explicit GetCommonDialogsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
833   }
834 
send(UserId user_id,int64 offset_chat_id,int32 limit)835   void send(UserId user_id, int64 offset_chat_id, int32 limit) {
836     user_id_ = user_id;
837     offset_chat_id_ = offset_chat_id;
838 
839     auto input_user = td_->contacts_manager_->get_input_user(user_id);
840     CHECK(input_user != nullptr);
841 
842     send_query(G()->net_query_creator().create(
843         telegram_api::messages_getCommonChats(std::move(input_user), offset_chat_id, limit)));
844   }
845 
on_result(BufferSlice packet)846   void on_result(BufferSlice packet) final {
847     auto result_ptr = fetch_result<telegram_api::messages_getCommonChats>(packet);
848     if (result_ptr.is_error()) {
849       return on_error(result_ptr.move_as_error());
850     }
851 
852     auto chats_ptr = result_ptr.move_as_ok();
853     LOG(INFO) << "Receive result for GetCommonDialogsQuery: " << to_string(chats_ptr);
854     switch (chats_ptr->get_id()) {
855       case telegram_api::messages_chats::ID: {
856         auto chats = move_tl_object_as<telegram_api::messages_chats>(chats_ptr);
857         td_->messages_manager_->on_get_common_dialogs(user_id_, offset_chat_id_, std::move(chats->chats_),
858                                                       narrow_cast<int32>(chats->chats_.size()));
859         break;
860       }
861       case telegram_api::messages_chatsSlice::ID: {
862         auto chats = move_tl_object_as<telegram_api::messages_chatsSlice>(chats_ptr);
863         td_->messages_manager_->on_get_common_dialogs(user_id_, offset_chat_id_, std::move(chats->chats_),
864                                                       chats->count_);
865         break;
866       }
867       default:
868         UNREACHABLE();
869     }
870 
871     promise_.set_value(Unit());
872   }
873 
on_error(Status status)874   void on_error(Status status) final {
875     promise_.set_error(std::move(status));
876   }
877 };
878 
879 class GetBlockedDialogsQuery final : public Td::ResultHandler {
880   Promise<td_api::object_ptr<td_api::messageSenders>> promise_;
881   int32 offset_;
882   int32 limit_;
883 
884  public:
GetBlockedDialogsQuery(Promise<td_api::object_ptr<td_api::messageSenders>> && promise)885   explicit GetBlockedDialogsQuery(Promise<td_api::object_ptr<td_api::messageSenders>> &&promise)
886       : promise_(std::move(promise)) {
887   }
888 
send(int32 offset,int32 limit)889   void send(int32 offset, int32 limit) {
890     offset_ = offset;
891     limit_ = limit;
892 
893     send_query(G()->net_query_creator().create(telegram_api::contacts_getBlocked(offset, limit)));
894   }
895 
on_result(BufferSlice packet)896   void on_result(BufferSlice packet) final {
897     auto result_ptr = fetch_result<telegram_api::contacts_getBlocked>(packet);
898     if (result_ptr.is_error()) {
899       return on_error(result_ptr.move_as_error());
900     }
901 
902     auto ptr = result_ptr.move_as_ok();
903     LOG(INFO) << "Receive result for GetBlockedDialogsQuery: " << to_string(ptr);
904 
905     switch (ptr->get_id()) {
906       case telegram_api::contacts_blocked::ID: {
907         auto blocked_peers = move_tl_object_as<telegram_api::contacts_blocked>(ptr);
908 
909         td_->contacts_manager_->on_get_users(std::move(blocked_peers->users_), "GetBlockedDialogsQuery");
910         td_->contacts_manager_->on_get_chats(std::move(blocked_peers->chats_), "GetBlockedDialogsQuery");
911         td_->messages_manager_->on_get_blocked_dialogs(offset_, limit_,
912                                                        narrow_cast<int32>(blocked_peers->blocked_.size()),
913                                                        std::move(blocked_peers->blocked_), std::move(promise_));
914         break;
915       }
916       case telegram_api::contacts_blockedSlice::ID: {
917         auto blocked_peers = move_tl_object_as<telegram_api::contacts_blockedSlice>(ptr);
918 
919         td_->contacts_manager_->on_get_users(std::move(blocked_peers->users_), "GetBlockedDialogsQuery");
920         td_->contacts_manager_->on_get_chats(std::move(blocked_peers->chats_), "GetBlockedDialogsQuery");
921         td_->messages_manager_->on_get_blocked_dialogs(offset_, limit_, blocked_peers->count_,
922                                                        std::move(blocked_peers->blocked_), std::move(promise_));
923         break;
924       }
925       default:
926         UNREACHABLE();
927     }
928   }
929 
on_error(Status status)930   void on_error(Status status) final {
931     promise_.set_error(std::move(status));
932   }
933 };
934 
935 class CreateChatQuery final : public Td::ResultHandler {
936   Promise<Unit> promise_;
937   int64 random_id_;
938 
939  public:
CreateChatQuery(Promise<Unit> && promise)940   explicit CreateChatQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
941   }
942 
send(vector<tl_object_ptr<telegram_api::InputUser>> && input_users,const string & title,int64 random_id)943   void send(vector<tl_object_ptr<telegram_api::InputUser>> &&input_users, const string &title, int64 random_id) {
944     random_id_ = random_id;
945     send_query(G()->net_query_creator().create(telegram_api::messages_createChat(std::move(input_users), title)));
946   }
947 
on_result(BufferSlice packet)948   void on_result(BufferSlice packet) final {
949     auto result_ptr = fetch_result<telegram_api::messages_createChat>(packet);
950     if (result_ptr.is_error()) {
951       return on_error(result_ptr.move_as_error());
952     }
953 
954     auto ptr = result_ptr.move_as_ok();
955     LOG(INFO) << "Receive result for CreateChatQuery: " << to_string(ptr);
956     td_->messages_manager_->on_create_new_dialog_success(random_id_, std::move(ptr), DialogType::Chat,
957                                                          std::move(promise_));
958   }
959 
on_error(Status status)960   void on_error(Status status) final {
961     td_->messages_manager_->on_create_new_dialog_fail(random_id_, std::move(status), std::move(promise_));
962   }
963 };
964 
965 class CreateChannelQuery final : public Td::ResultHandler {
966   Promise<Unit> promise_;
967   int64 random_id_;
968 
969  public:
CreateChannelQuery(Promise<Unit> && promise)970   explicit CreateChannelQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
971   }
972 
send(const string & title,bool is_megagroup,const string & about,const DialogLocation & location,bool for_import,int64 random_id)973   void send(const string &title, bool is_megagroup, const string &about, const DialogLocation &location,
974             bool for_import, int64 random_id) {
975     int32 flags = 0;
976     if (is_megagroup) {
977       flags |= telegram_api::channels_createChannel::MEGAGROUP_MASK;
978     } else {
979       flags |= telegram_api::channels_createChannel::BROADCAST_MASK;
980     }
981     if (!location.empty()) {
982       flags |= telegram_api::channels_createChannel::GEO_POINT_MASK;
983     }
984     if (for_import) {
985       flags |= telegram_api::channels_createChannel::FOR_IMPORT_MASK;
986     }
987 
988     random_id_ = random_id;
989     send_query(G()->net_query_creator().create(
990         telegram_api::channels_createChannel(flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, title,
991                                              about, location.get_input_geo_point(), location.get_address())));
992   }
993 
on_result(BufferSlice packet)994   void on_result(BufferSlice packet) final {
995     auto result_ptr = fetch_result<telegram_api::channels_createChannel>(packet);
996     if (result_ptr.is_error()) {
997       return on_error(result_ptr.move_as_error());
998     }
999 
1000     auto ptr = result_ptr.move_as_ok();
1001     LOG(INFO) << "Receive result for CreateChannelQuery: " << to_string(ptr);
1002     td_->messages_manager_->on_create_new_dialog_success(random_id_, std::move(ptr), DialogType::Channel,
1003                                                          std::move(promise_));
1004   }
1005 
on_error(Status status)1006   void on_error(Status status) final {
1007     td_->messages_manager_->on_create_new_dialog_fail(random_id_, std::move(status), std::move(promise_));
1008   }
1009 };
1010 
1011 class CheckHistoryImportQuery final : public Td::ResultHandler {
1012   Promise<tl_object_ptr<td_api::MessageFileType>> promise_;
1013 
1014  public:
CheckHistoryImportQuery(Promise<tl_object_ptr<td_api::MessageFileType>> && promise)1015   explicit CheckHistoryImportQuery(Promise<tl_object_ptr<td_api::MessageFileType>> &&promise)
1016       : promise_(std::move(promise)) {
1017   }
1018 
send(const string & message_file_head)1019   void send(const string &message_file_head) {
1020     send_query(G()->net_query_creator().create(telegram_api::messages_checkHistoryImport(message_file_head)));
1021   }
1022 
on_result(BufferSlice packet)1023   void on_result(BufferSlice packet) final {
1024     auto result_ptr = fetch_result<telegram_api::messages_checkHistoryImport>(packet);
1025     if (result_ptr.is_error()) {
1026       return on_error(result_ptr.move_as_error());
1027     }
1028 
1029     auto ptr = result_ptr.move_as_ok();
1030     LOG(INFO) << "Receive result for CheckHistoryImportQuery: " << to_string(ptr);
1031     auto file_type = [&]() -> td_api::object_ptr<td_api::MessageFileType> {
1032       if (ptr->pm_) {
1033         return td_api::make_object<td_api::messageFileTypePrivate>(ptr->title_);
1034       } else if (ptr->group_) {
1035         return td_api::make_object<td_api::messageFileTypeGroup>(ptr->title_);
1036       } else {
1037         return td_api::make_object<td_api::messageFileTypeUnknown>();
1038       }
1039     }();
1040     promise_.set_value(std::move(file_type));
1041   }
1042 
on_error(Status status)1043   void on_error(Status status) final {
1044     promise_.set_error(std::move(status));
1045   }
1046 };
1047 
1048 class CheckHistoryImportPeerQuery final : public Td::ResultHandler {
1049   Promise<string> promise_;
1050   DialogId dialog_id_;
1051 
1052  public:
CheckHistoryImportPeerQuery(Promise<string> && promise)1053   explicit CheckHistoryImportPeerQuery(Promise<string> &&promise) : promise_(std::move(promise)) {
1054   }
1055 
send(DialogId dialog_id)1056   void send(DialogId dialog_id) {
1057     dialog_id_ = dialog_id;
1058     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1059     CHECK(input_peer != nullptr);
1060     send_query(G()->net_query_creator().create(telegram_api::messages_checkHistoryImportPeer(std::move(input_peer))));
1061   }
1062 
on_result(BufferSlice packet)1063   void on_result(BufferSlice packet) final {
1064     auto result_ptr = fetch_result<telegram_api::messages_checkHistoryImportPeer>(packet);
1065     if (result_ptr.is_error()) {
1066       return on_error(result_ptr.move_as_error());
1067     }
1068 
1069     auto ptr = result_ptr.move_as_ok();
1070     LOG(INFO) << "Receive result for CheckHistoryImportPeerQuery: " << to_string(ptr);
1071     promise_.set_value(std::move(ptr->confirm_text_));
1072   }
1073 
on_error(Status status)1074   void on_error(Status status) final {
1075     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "CheckHistoryImportPeerQuery");
1076     promise_.set_error(std::move(status));
1077   }
1078 };
1079 
1080 class InitHistoryImportQuery final : public Td::ResultHandler {
1081   Promise<Unit> promise_;
1082   FileId file_id_;
1083   DialogId dialog_id_;
1084   vector<FileId> attached_file_ids_;
1085 
1086  public:
InitHistoryImportQuery(Promise<Unit> && promise)1087   explicit InitHistoryImportQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1088   }
1089 
send(DialogId dialog_id,FileId file_id,tl_object_ptr<telegram_api::InputFile> && input_file,vector<FileId> attached_file_ids)1090   void send(DialogId dialog_id, FileId file_id, tl_object_ptr<telegram_api::InputFile> &&input_file,
1091             vector<FileId> attached_file_ids) {
1092     CHECK(input_file != nullptr);
1093     file_id_ = file_id;
1094     dialog_id_ = dialog_id;
1095     attached_file_ids_ = std::move(attached_file_ids);
1096 
1097     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1098     CHECK(input_peer != nullptr);
1099     send_query(G()->net_query_creator().create(telegram_api::messages_initHistoryImport(
1100         std::move(input_peer), std::move(input_file), narrow_cast<int32>(attached_file_ids_.size()))));
1101   }
1102 
on_result(BufferSlice packet)1103   void on_result(BufferSlice packet) final {
1104     auto result_ptr = fetch_result<telegram_api::messages_initHistoryImport>(packet);
1105     if (result_ptr.is_error()) {
1106       return on_error(result_ptr.move_as_error());
1107     }
1108 
1109     td_->file_manager_->delete_partial_remote_location(file_id_);
1110 
1111     auto ptr = result_ptr.move_as_ok();
1112     td_->messages_manager_->start_import_messages(dialog_id_, ptr->id_, std::move(attached_file_ids_),
1113                                                   std::move(promise_));
1114   }
1115 
on_error(Status status)1116   void on_error(Status status) final {
1117     if (FileReferenceManager::is_file_reference_error(status)) {
1118       LOG(ERROR) << "Receive file reference error " << status;
1119     }
1120     if (begins_with(status.message(), "FILE_PART_") && ends_with(status.message(), "_MISSING")) {
1121       // TODO support FILE_PART_*_MISSING
1122     }
1123 
1124     td_->file_manager_->delete_partial_remote_location(file_id_);
1125 
1126     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "InitHistoryImportQuery");
1127     promise_.set_error(std::move(status));
1128   }
1129 };
1130 
1131 class UploadImportedMediaQuery final : public Td::ResultHandler {
1132   Promise<Unit> promise_;
1133   DialogId dialog_id_;
1134   int64 import_id_;
1135   FileId file_id_;
1136 
1137  public:
UploadImportedMediaQuery(Promise<Unit> && promise)1138   explicit UploadImportedMediaQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1139   }
1140 
send(DialogId dialog_id,int64 import_id,const string & file_name,FileId file_id,tl_object_ptr<telegram_api::InputMedia> && input_media)1141   void send(DialogId dialog_id, int64 import_id, const string &file_name, FileId file_id,
1142             tl_object_ptr<telegram_api::InputMedia> &&input_media) {
1143     CHECK(input_media != nullptr);
1144     dialog_id_ = dialog_id;
1145     import_id_ = import_id;
1146     file_id_ = file_id;
1147 
1148     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1149     if (input_peer == nullptr) {
1150       return on_error(Status::Error(400, "Can't access the chat"));
1151     }
1152 
1153     send_query(G()->net_query_creator().create(telegram_api::messages_uploadImportedMedia(
1154         std::move(input_peer), import_id, file_name, std::move(input_media))));
1155   }
1156 
on_result(BufferSlice packet)1157   void on_result(BufferSlice packet) final {
1158     auto result_ptr = fetch_result<telegram_api::messages_uploadImportedMedia>(packet);
1159     if (result_ptr.is_error()) {
1160       return on_error(result_ptr.move_as_error());
1161     }
1162 
1163     td_->file_manager_->delete_partial_remote_location(file_id_);
1164 
1165     // ignore response
1166 
1167     promise_.set_value(Unit());
1168   }
1169 
on_error(Status status)1170   void on_error(Status status) final {
1171     if (FileReferenceManager::is_file_reference_error(status)) {
1172       LOG(ERROR) << "Receive file reference error " << status;
1173     }
1174     if (begins_with(status.message(), "FILE_PART_") && ends_with(status.message(), "_MISSING")) {
1175       // TODO support FILE_PART_*_MISSING
1176     }
1177 
1178     td_->file_manager_->delete_partial_remote_location(file_id_);
1179     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "UploadImportedMediaQuery");
1180     promise_.set_error(std::move(status));
1181   }
1182 };
1183 
1184 class StartImportHistoryQuery final : public Td::ResultHandler {
1185   Promise<Unit> promise_;
1186   DialogId dialog_id_;
1187 
1188  public:
StartImportHistoryQuery(Promise<Unit> && promise)1189   explicit StartImportHistoryQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1190   }
1191 
send(DialogId dialog_id,int64 import_id)1192   void send(DialogId dialog_id, int64 import_id) {
1193     dialog_id_ = dialog_id;
1194 
1195     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1196     CHECK(input_peer != nullptr);
1197 
1198     send_query(
1199         G()->net_query_creator().create(telegram_api::messages_startHistoryImport(std::move(input_peer), import_id)));
1200   }
1201 
on_result(BufferSlice packet)1202   void on_result(BufferSlice packet) final {
1203     auto result_ptr = fetch_result<telegram_api::messages_startHistoryImport>(packet);
1204     if (result_ptr.is_error()) {
1205       return on_error(result_ptr.move_as_error());
1206     }
1207 
1208     if (!result_ptr.ok()) {
1209       return on_error(Status::Error(500, "Import history returned false"));
1210     }
1211     promise_.set_value(Unit());
1212   }
1213 
on_error(Status status)1214   void on_error(Status status) final {
1215     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "StartImportHistoryQuery");
1216     promise_.set_error(std::move(status));
1217   }
1218 };
1219 
1220 class EditDialogPhotoQuery final : public Td::ResultHandler {
1221   Promise<Unit> promise_;
1222   FileId file_id_;
1223   bool was_uploaded_ = false;
1224   string file_reference_;
1225   DialogId dialog_id_;
1226 
1227  public:
EditDialogPhotoQuery(Promise<Unit> && promise)1228   explicit EditDialogPhotoQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1229   }
1230 
send(DialogId dialog_id,FileId file_id,tl_object_ptr<telegram_api::InputChatPhoto> && input_chat_photo)1231   void send(DialogId dialog_id, FileId file_id, tl_object_ptr<telegram_api::InputChatPhoto> &&input_chat_photo) {
1232     CHECK(input_chat_photo != nullptr);
1233     file_id_ = file_id;
1234     was_uploaded_ = FileManager::extract_was_uploaded(input_chat_photo);
1235     file_reference_ = FileManager::extract_file_reference(input_chat_photo);
1236     dialog_id_ = dialog_id;
1237 
1238     switch (dialog_id.get_type()) {
1239       case DialogType::Chat:
1240         send_query(G()->net_query_creator().create(
1241             telegram_api::messages_editChatPhoto(dialog_id.get_chat_id().get(), std::move(input_chat_photo))));
1242         break;
1243       case DialogType::Channel: {
1244         auto channel_id = dialog_id.get_channel_id();
1245         auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
1246         CHECK(input_channel != nullptr);
1247         send_query(G()->net_query_creator().create(
1248             telegram_api::channels_editPhoto(std::move(input_channel), std::move(input_chat_photo))));
1249         break;
1250       }
1251       default:
1252         UNREACHABLE();
1253     }
1254   }
1255 
on_result(BufferSlice packet)1256   void on_result(BufferSlice packet) final {
1257     static_assert(std::is_same<telegram_api::messages_editChatPhoto::ReturnType,
1258                                telegram_api::channels_editPhoto::ReturnType>::value,
1259                   "");
1260     auto result_ptr = fetch_result<telegram_api::messages_editChatPhoto>(packet);
1261     if (result_ptr.is_error()) {
1262       return on_error(result_ptr.move_as_error());
1263     }
1264 
1265     auto ptr = result_ptr.move_as_ok();
1266     LOG(INFO) << "Receive result for EditDialogPhotoQuery: " << to_string(ptr);
1267 
1268     if (file_id_.is_valid() && was_uploaded_) {
1269       td_->file_manager_->delete_partial_remote_location(file_id_);
1270     }
1271 
1272     td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
1273   }
1274 
on_error(Status status)1275   void on_error(Status status) final {
1276     if (file_id_.is_valid() && was_uploaded_) {
1277       td_->file_manager_->delete_partial_remote_location(file_id_);
1278     }
1279     if (!td_->auth_manager_->is_bot() && FileReferenceManager::is_file_reference_error(status)) {
1280       if (file_id_.is_valid() && !was_uploaded_) {
1281         VLOG(file_references) << "Receive " << status << " for " << file_id_;
1282         td_->file_manager_->delete_file_reference(file_id_, file_reference_);
1283         td_->messages_manager_->upload_dialog_photo(dialog_id_, file_id_, false, 0.0, false, std::move(promise_), {-1});
1284         return;
1285       } else {
1286         LOG(ERROR) << "Receive file reference error, but file_id = " << file_id_
1287                    << ", was_uploaded = " << was_uploaded_;
1288       }
1289     }
1290 
1291     if (status.message() == "CHAT_NOT_MODIFIED") {
1292       if (!td_->auth_manager_->is_bot()) {
1293         promise_.set_value(Unit());
1294         return;
1295       }
1296     } else {
1297       td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "EditDialogPhotoQuery");
1298     }
1299     td_->updates_manager_->get_difference("EditDialogPhotoQuery");
1300     promise_.set_error(std::move(status));
1301   }
1302 };
1303 
1304 class EditDialogTitleQuery final : public Td::ResultHandler {
1305   Promise<Unit> promise_;
1306   DialogId dialog_id_;
1307 
1308  public:
EditDialogTitleQuery(Promise<Unit> && promise)1309   explicit EditDialogTitleQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1310   }
1311 
send(DialogId dialog_id,const string & title)1312   void send(DialogId dialog_id, const string &title) {
1313     dialog_id_ = dialog_id;
1314     switch (dialog_id.get_type()) {
1315       case DialogType::Chat:
1316         send_query(G()->net_query_creator().create(
1317             telegram_api::messages_editChatTitle(dialog_id.get_chat_id().get(), title)));
1318         break;
1319       case DialogType::Channel: {
1320         auto channel_id = dialog_id.get_channel_id();
1321         auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
1322         CHECK(input_channel != nullptr);
1323         send_query(G()->net_query_creator().create(telegram_api::channels_editTitle(std::move(input_channel), title)));
1324         break;
1325       }
1326       default:
1327         UNREACHABLE();
1328     }
1329   }
1330 
on_result(BufferSlice packet)1331   void on_result(BufferSlice packet) final {
1332     static_assert(std::is_same<telegram_api::messages_editChatTitle::ReturnType,
1333                                telegram_api::channels_editTitle::ReturnType>::value,
1334                   "");
1335     auto result_ptr = fetch_result<telegram_api::messages_editChatTitle>(packet);
1336     if (result_ptr.is_error()) {
1337       return on_error(result_ptr.move_as_error());
1338     }
1339 
1340     auto ptr = result_ptr.move_as_ok();
1341     LOG(INFO) << "Receive result for EditDialogTitleQuery: " << to_string(ptr);
1342     td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
1343   }
1344 
on_error(Status status)1345   void on_error(Status status) final {
1346     td_->updates_manager_->get_difference("EditDialogTitleQuery");
1347 
1348     if (status.message() == "CHAT_NOT_MODIFIED") {
1349       if (!td_->auth_manager_->is_bot()) {
1350         promise_.set_value(Unit());
1351         return;
1352       }
1353     } else {
1354       td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "EditDialogTitleQuery");
1355     }
1356     promise_.set_error(std::move(status));
1357   }
1358 };
1359 
1360 class SetChatThemeQuery final : public Td::ResultHandler {
1361   Promise<Unit> promise_;
1362   DialogId dialog_id_;
1363 
1364  public:
SetChatThemeQuery(Promise<Unit> && promise)1365   explicit SetChatThemeQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1366   }
1367 
send(DialogId dialog_id,const string & theme_name)1368   void send(DialogId dialog_id, const string &theme_name) {
1369     dialog_id_ = dialog_id;
1370     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1371     CHECK(input_peer != nullptr);
1372     send_query(G()->net_query_creator().create(telegram_api::messages_setChatTheme(std::move(input_peer), theme_name)));
1373   }
1374 
on_result(BufferSlice packet)1375   void on_result(BufferSlice packet) final {
1376     auto result_ptr = fetch_result<telegram_api::messages_setChatTheme>(packet);
1377     if (result_ptr.is_error()) {
1378       return on_error(result_ptr.move_as_error());
1379     }
1380 
1381     auto ptr = result_ptr.move_as_ok();
1382     LOG(INFO) << "Receive result for SetChatThemeQuery: " << to_string(ptr);
1383     td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
1384   }
1385 
on_error(Status status)1386   void on_error(Status status) final {
1387     if (status.message() == "CHAT_NOT_MODIFIED") {
1388       if (!td_->auth_manager_->is_bot()) {
1389         promise_.set_value(Unit());
1390         return;
1391       }
1392     } else {
1393       td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "SetChatThemeQuery");
1394     }
1395     promise_.set_error(std::move(status));
1396   }
1397 };
1398 
1399 class SetHistoryTtlQuery final : public Td::ResultHandler {
1400   Promise<Unit> promise_;
1401   DialogId dialog_id_;
1402 
1403  public:
SetHistoryTtlQuery(Promise<Unit> && promise)1404   explicit SetHistoryTtlQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1405   }
1406 
send(DialogId dialog_id,int32 period)1407   void send(DialogId dialog_id, int32 period) {
1408     dialog_id_ = dialog_id;
1409 
1410     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1411     CHECK(input_peer != nullptr);
1412 
1413     send_query(G()->net_query_creator().create(telegram_api::messages_setHistoryTTL(std::move(input_peer), period)));
1414   }
1415 
on_result(BufferSlice packet)1416   void on_result(BufferSlice packet) final {
1417     auto result_ptr = fetch_result<telegram_api::messages_setHistoryTTL>(packet);
1418     if (result_ptr.is_error()) {
1419       return on_error(result_ptr.move_as_error());
1420     }
1421 
1422     auto ptr = result_ptr.move_as_ok();
1423     LOG(INFO) << "Receive result for SetHistoryTtlQuery: " << to_string(ptr);
1424     td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
1425   }
1426 
on_error(Status status)1427   void on_error(Status status) final {
1428     if (status.message() == "CHAT_NOT_MODIFIED") {
1429       if (!td_->auth_manager_->is_bot()) {
1430         promise_.set_value(Unit());
1431         return;
1432       }
1433     } else {
1434       td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "SetHistoryTtlQuery");
1435     }
1436     promise_.set_error(std::move(status));
1437   }
1438 };
1439 
1440 class EditChatDefaultBannedRightsQuery final : public Td::ResultHandler {
1441   Promise<Unit> promise_;
1442   DialogId dialog_id_;
1443 
1444  public:
EditChatDefaultBannedRightsQuery(Promise<Unit> && promise)1445   explicit EditChatDefaultBannedRightsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1446   }
1447 
send(DialogId dialog_id,RestrictedRights permissions)1448   void send(DialogId dialog_id, RestrictedRights permissions) {
1449     dialog_id_ = dialog_id;
1450     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1451     CHECK(input_peer != nullptr);
1452     send_query(G()->net_query_creator().create(telegram_api::messages_editChatDefaultBannedRights(
1453         std::move(input_peer), permissions.get_chat_banned_rights())));
1454   }
1455 
on_result(BufferSlice packet)1456   void on_result(BufferSlice packet) final {
1457     auto result_ptr = fetch_result<telegram_api::messages_editChatDefaultBannedRights>(packet);
1458     if (result_ptr.is_error()) {
1459       return on_error(result_ptr.move_as_error());
1460     }
1461 
1462     auto ptr = result_ptr.move_as_ok();
1463     LOG(INFO) << "Receive result for EditChatDefaultBannedRightsQuery: " << to_string(ptr);
1464     td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
1465   }
1466 
on_error(Status status)1467   void on_error(Status status) final {
1468     if (status.message() == "CHAT_NOT_MODIFIED") {
1469       if (!td_->auth_manager_->is_bot()) {
1470         promise_.set_value(Unit());
1471         return;
1472       }
1473     } else {
1474       td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "EditChatDefaultBannedRightsQuery");
1475     }
1476     promise_.set_error(std::move(status));
1477   }
1478 };
1479 
1480 class ToggleNoForwardsQuery final : public Td::ResultHandler {
1481   Promise<Unit> promise_;
1482   DialogId dialog_id_;
1483 
1484  public:
ToggleNoForwardsQuery(Promise<Unit> && promise)1485   explicit ToggleNoForwardsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1486   }
1487 
send(DialogId dialog_id,bool has_protected_content)1488   void send(DialogId dialog_id, bool has_protected_content) {
1489     dialog_id_ = dialog_id;
1490     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
1491     CHECK(input_peer != nullptr);
1492     send_query(G()->net_query_creator().create(
1493         telegram_api::messages_toggleNoForwards(std::move(input_peer), has_protected_content)));
1494   }
1495 
on_result(BufferSlice packet)1496   void on_result(BufferSlice packet) final {
1497     auto result_ptr = fetch_result<telegram_api::messages_toggleNoForwards>(packet);
1498     if (result_ptr.is_error()) {
1499       return on_error(result_ptr.move_as_error());
1500     }
1501 
1502     auto ptr = result_ptr.move_as_ok();
1503     LOG(INFO) << "Receive result for ToggleNoForwardsQuery: " << to_string(ptr);
1504     td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
1505   }
1506 
on_error(Status status)1507   void on_error(Status status) final {
1508     if (status.message() == "CHAT_NOT_MODIFIED") {
1509       promise_.set_value(Unit());
1510       return;
1511     } else {
1512       td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "ToggleNoForwardsQuery");
1513     }
1514     promise_.set_error(std::move(status));
1515   }
1516 };
1517 
1518 class SaveDraftMessageQuery final : public Td::ResultHandler {
1519   Promise<Unit> promise_;
1520   DialogId dialog_id_;
1521 
1522  public:
SaveDraftMessageQuery(Promise<Unit> && promise)1523   explicit SaveDraftMessageQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1524   }
1525 
send(DialogId dialog_id,const unique_ptr<DraftMessage> & draft_message)1526   void send(DialogId dialog_id, const unique_ptr<DraftMessage> &draft_message) {
1527     dialog_id_ = dialog_id;
1528 
1529     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1530     if (input_peer == nullptr) {
1531       LOG(INFO) << "Can't update draft message because have no write access to " << dialog_id;
1532       return on_error(Status::Error(400, "Can't save draft message"));
1533     }
1534 
1535     int32 flags = 0;
1536     ServerMessageId reply_to_message_id;
1537     if (draft_message != nullptr) {
1538       if (draft_message->reply_to_message_id.is_valid() && draft_message->reply_to_message_id.is_server()) {
1539         reply_to_message_id = draft_message->reply_to_message_id.get_server_message_id();
1540         flags |= MessagesManager::SEND_MESSAGE_FLAG_IS_REPLY;
1541       }
1542       if (draft_message->input_message_text.disable_web_page_preview) {
1543         flags |= MessagesManager::SEND_MESSAGE_FLAG_DISABLE_WEB_PAGE_PREVIEW;
1544       }
1545       if (!draft_message->input_message_text.text.entities.empty()) {
1546         flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_ENTITIES;
1547       }
1548     }
1549 
1550     send_query(G()->net_query_creator().create(telegram_api::messages_saveDraft(
1551         flags, false /*ignored*/, reply_to_message_id.get(), std::move(input_peer),
1552         draft_message == nullptr ? "" : draft_message->input_message_text.text.text,
1553         draft_message == nullptr
1554             ? vector<tl_object_ptr<telegram_api::MessageEntity>>()
1555             : get_input_message_entities(td_->contacts_manager_.get(), draft_message->input_message_text.text.entities,
1556                                          "SaveDraftMessageQuery"))));
1557   }
1558 
on_result(BufferSlice packet)1559   void on_result(BufferSlice packet) final {
1560     auto result_ptr = fetch_result<telegram_api::messages_saveDraft>(packet);
1561     if (result_ptr.is_error()) {
1562       return on_error(result_ptr.move_as_error());
1563     }
1564 
1565     bool result = result_ptr.ok();
1566     if (!result) {
1567       on_error(Status::Error(400, "Save draft failed"));
1568     }
1569 
1570     promise_.set_value(Unit());
1571   }
1572 
on_error(Status status)1573   void on_error(Status status) final {
1574     if (!td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "SaveDraftMessageQuery")) {
1575       LOG(ERROR) << "Receive error for SaveDraftMessageQuery: " << status;
1576     }
1577     promise_.set_error(std::move(status));
1578   }
1579 };
1580 
1581 class ClearAllDraftsQuery final : public Td::ResultHandler {
1582   Promise<Unit> promise_;
1583 
1584  public:
ClearAllDraftsQuery(Promise<Unit> && promise)1585   explicit ClearAllDraftsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1586   }
1587 
send()1588   void send() {
1589     send_query(G()->net_query_creator().create(telegram_api::messages_clearAllDrafts()));
1590   }
1591 
on_result(BufferSlice packet)1592   void on_result(BufferSlice packet) final {
1593     auto result_ptr = fetch_result<telegram_api::messages_clearAllDrafts>(packet);
1594     if (result_ptr.is_error()) {
1595       return on_error(result_ptr.move_as_error());
1596     }
1597 
1598     LOG(INFO) << "Receive result for ClearAllDraftsQuery: " << result_ptr.ok();
1599     promise_.set_value(Unit());
1600   }
1601 
on_error(Status status)1602   void on_error(Status status) final {
1603     if (!G()->is_expected_error(status)) {
1604       LOG(ERROR) << "Receive error for ClearAllDraftsQuery: " << status;
1605     }
1606     promise_.set_error(std::move(status));
1607   }
1608 };
1609 
1610 class ToggleDialogPinQuery final : public Td::ResultHandler {
1611   Promise<Unit> promise_;
1612   DialogId dialog_id_;
1613   bool is_pinned_;
1614 
1615  public:
ToggleDialogPinQuery(Promise<Unit> && promise)1616   explicit ToggleDialogPinQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1617   }
1618 
send(DialogId dialog_id,bool is_pinned)1619   void send(DialogId dialog_id, bool is_pinned) {
1620     dialog_id_ = dialog_id;
1621     is_pinned_ = is_pinned;
1622 
1623     auto input_peer = td_->messages_manager_->get_input_dialog_peer(dialog_id, AccessRights::Read);
1624     if (input_peer == nullptr) {
1625       return on_error(Status::Error(400, "Can't access the chat"));
1626     }
1627 
1628     int32 flags = 0;
1629     if (is_pinned) {
1630       flags |= telegram_api::messages_toggleDialogPin::PINNED_MASK;
1631     }
1632     send_query(G()->net_query_creator().create(
1633         telegram_api::messages_toggleDialogPin(flags, false /*ignored*/, std::move(input_peer))));
1634   }
1635 
on_result(BufferSlice packet)1636   void on_result(BufferSlice packet) final {
1637     auto result_ptr = fetch_result<telegram_api::messages_toggleDialogPin>(packet);
1638     if (result_ptr.is_error()) {
1639       return on_error(result_ptr.move_as_error());
1640     }
1641 
1642     bool result = result_ptr.ok();
1643     if (!result) {
1644       on_error(Status::Error(400, "Toggle dialog pin failed"));
1645     }
1646 
1647     promise_.set_value(Unit());
1648   }
1649 
on_error(Status status)1650   void on_error(Status status) final {
1651     if (!td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "ToggleDialogPinQuery")) {
1652       LOG(ERROR) << "Receive error for ToggleDialogPinQuery: " << status;
1653     }
1654     td_->messages_manager_->on_update_pinned_dialogs(FolderId::main());
1655     td_->messages_manager_->on_update_pinned_dialogs(FolderId::archive());
1656     promise_.set_error(std::move(status));
1657   }
1658 };
1659 
1660 class ReorderPinnedDialogsQuery final : public Td::ResultHandler {
1661   FolderId folder_id_;
1662   Promise<Unit> promise_;
1663 
1664  public:
ReorderPinnedDialogsQuery(Promise<Unit> && promise)1665   explicit ReorderPinnedDialogsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1666   }
1667 
send(FolderId folder_id,const vector<DialogId> & dialog_ids)1668   void send(FolderId folder_id, const vector<DialogId> &dialog_ids) {
1669     folder_id_ = folder_id;
1670     int32 flags = telegram_api::messages_reorderPinnedDialogs::FORCE_MASK;
1671     send_query(G()->net_query_creator().create(telegram_api::messages_reorderPinnedDialogs(
1672         flags, true /*ignored*/, folder_id.get(),
1673         td_->messages_manager_->get_input_dialog_peers(dialog_ids, AccessRights::Read))));
1674   }
1675 
on_result(BufferSlice packet)1676   void on_result(BufferSlice packet) final {
1677     auto result_ptr = fetch_result<telegram_api::messages_reorderPinnedDialogs>(packet);
1678     if (result_ptr.is_error()) {
1679       return on_error(result_ptr.move_as_error());
1680     }
1681 
1682     bool result = result_ptr.move_as_ok();
1683     if (!result) {
1684       return on_error(Status::Error(400, "Result is false"));
1685     }
1686     promise_.set_value(Unit());
1687   }
1688 
on_error(Status status)1689   void on_error(Status status) final {
1690     if (!G()->is_expected_error(status)) {
1691       LOG(ERROR) << "Receive error for ReorderPinnedDialogsQuery: " << status;
1692     }
1693     td_->messages_manager_->on_update_pinned_dialogs(folder_id_);
1694     promise_.set_error(std::move(status));
1695   }
1696 };
1697 
1698 class ToggleDialogUnreadMarkQuery final : public Td::ResultHandler {
1699   Promise<Unit> promise_;
1700   DialogId dialog_id_;
1701   bool is_marked_as_unread_;
1702 
1703  public:
ToggleDialogUnreadMarkQuery(Promise<Unit> && promise)1704   explicit ToggleDialogUnreadMarkQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1705   }
1706 
send(DialogId dialog_id,bool is_marked_as_unread)1707   void send(DialogId dialog_id, bool is_marked_as_unread) {
1708     dialog_id_ = dialog_id;
1709     is_marked_as_unread_ = is_marked_as_unread;
1710 
1711     auto input_peer = td_->messages_manager_->get_input_dialog_peer(dialog_id, AccessRights::Read);
1712     if (input_peer == nullptr) {
1713       return on_error(Status::Error(400, "Can't access the chat"));
1714     }
1715 
1716     int32 flags = 0;
1717     if (is_marked_as_unread) {
1718       flags |= telegram_api::messages_markDialogUnread::UNREAD_MASK;
1719     }
1720     send_query(G()->net_query_creator().create(
1721         telegram_api::messages_markDialogUnread(flags, false /*ignored*/, std::move(input_peer))));
1722   }
1723 
on_result(BufferSlice packet)1724   void on_result(BufferSlice packet) final {
1725     auto result_ptr = fetch_result<telegram_api::messages_markDialogUnread>(packet);
1726     if (result_ptr.is_error()) {
1727       return on_error(result_ptr.move_as_error());
1728     }
1729 
1730     bool result = result_ptr.ok();
1731     if (!result) {
1732       on_error(Status::Error(400, "Toggle dialog mark failed"));
1733     }
1734 
1735     promise_.set_value(Unit());
1736   }
1737 
on_error(Status status)1738   void on_error(Status status) final {
1739     if (!td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "ToggleDialogUnreadMarkQuery")) {
1740       LOG(ERROR) << "Receive error for ToggleDialogUnreadMarkQuery: " << status;
1741     }
1742     if (!G()->close_flag()) {
1743       td_->messages_manager_->on_update_dialog_is_marked_as_unread(dialog_id_, !is_marked_as_unread_);
1744     }
1745     promise_.set_error(std::move(status));
1746   }
1747 };
1748 
1749 class ToggleDialogIsBlockedActor final : public NetActorOnce {
1750   Promise<Unit> promise_;
1751   DialogId dialog_id_;
1752   bool is_blocked_;
1753 
1754  public:
ToggleDialogIsBlockedActor(Promise<Unit> && promise)1755   explicit ToggleDialogIsBlockedActor(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1756   }
1757 
send(DialogId dialog_id,bool is_blocked,uint64 sequence_dispatcher_id)1758   void send(DialogId dialog_id, bool is_blocked, uint64 sequence_dispatcher_id) {
1759     dialog_id_ = dialog_id;
1760     is_blocked_ = is_blocked;
1761 
1762     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Know);
1763     CHECK(input_peer != nullptr && input_peer->get_id() != telegram_api::inputPeerEmpty::ID);
1764     auto query = is_blocked ? G()->net_query_creator().create(telegram_api::contacts_block(std::move(input_peer)))
1765                             : G()->net_query_creator().create(telegram_api::contacts_unblock(std::move(input_peer)));
1766     send_closure(td_->messages_manager_->sequence_dispatcher_, &MultiSequenceDispatcher::send_with_callback,
1767                  std::move(query), actor_shared(this), sequence_dispatcher_id);
1768   }
1769 
on_result(BufferSlice packet)1770   void on_result(BufferSlice packet) final {
1771     static_assert(
1772         std::is_same<telegram_api::contacts_block::ReturnType, telegram_api::contacts_unblock::ReturnType>::value, "");
1773     auto result_ptr = fetch_result<telegram_api::contacts_block>(packet);
1774     if (result_ptr.is_error()) {
1775       return on_error(result_ptr.move_as_error());
1776     }
1777 
1778     bool result = result_ptr.ok();
1779     LOG_IF(WARNING, !result) << "Block/Unblock " << dialog_id_ << " has failed";
1780 
1781     promise_.set_value(Unit());
1782   }
1783 
on_error(Status status)1784   void on_error(Status status) final {
1785     if (!td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "ToggleDialogIsBlockedActor")) {
1786       LOG(ERROR) << "Receive error for ToggleDialogIsBlockedActor: " << status;
1787     }
1788     if (!G()->close_flag()) {
1789       td_->messages_manager_->on_update_dialog_is_blocked(dialog_id_, !is_blocked_);
1790       td_->messages_manager_->get_dialog_info_full(dialog_id_, Auto(), "ToggleDialogIsBlockedActor");
1791       td_->messages_manager_->reget_dialog_action_bar(dialog_id_, "ToggleDialogIsBlockedActor");
1792     }
1793     promise_.set_error(std::move(status));
1794   }
1795 };
1796 
1797 class GetMessagesViewsQuery final : public Td::ResultHandler {
1798   DialogId dialog_id_;
1799   vector<MessageId> message_ids_;
1800 
1801  public:
send(DialogId dialog_id,vector<MessageId> && message_ids,bool increment_view_counter)1802   void send(DialogId dialog_id, vector<MessageId> &&message_ids, bool increment_view_counter) {
1803     dialog_id_ = dialog_id;
1804     message_ids_ = std::move(message_ids);
1805 
1806     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
1807     if (input_peer == nullptr) {
1808       return on_error(Status::Error(400, "Can't access the chat"));
1809     }
1810 
1811     send_query(G()->net_query_creator().create(telegram_api::messages_getMessagesViews(
1812         std::move(input_peer), MessagesManager::get_server_message_ids(message_ids_), increment_view_counter)));
1813   }
1814 
on_result(BufferSlice packet)1815   void on_result(BufferSlice packet) final {
1816     auto result_ptr = fetch_result<telegram_api::messages_getMessagesViews>(packet);
1817     if (result_ptr.is_error()) {
1818       return on_error(result_ptr.move_as_error());
1819     }
1820 
1821     auto result = result_ptr.move_as_ok();
1822     auto interaction_infos = std::move(result->views_);
1823     if (message_ids_.size() != interaction_infos.size()) {
1824       return on_error(Status::Error(500, "Wrong number of message views returned"));
1825     }
1826     td_->contacts_manager_->on_get_users(std::move(result->users_), "GetMessagesViewsQuery");
1827     td_->contacts_manager_->on_get_chats(std::move(result->chats_), "GetMessagesViewsQuery");
1828     for (size_t i = 0; i < message_ids_.size(); i++) {
1829       FullMessageId full_message_id{dialog_id_, message_ids_[i]};
1830 
1831       auto *info = interaction_infos[i].get();
1832       auto flags = info->flags_;
1833       auto view_count = (flags & telegram_api::messageViews::VIEWS_MASK) != 0 ? info->views_ : 0;
1834       auto forward_count = (flags & telegram_api::messageViews::FORWARDS_MASK) != 0 ? info->forwards_ : 0;
1835       td_->messages_manager_->on_update_message_interaction_info(full_message_id, view_count, forward_count, true,
1836                                                                  std::move(info->replies_));
1837     }
1838   }
1839 
on_error(Status status)1840   void on_error(Status status) final {
1841     if (!td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetMessagesViewsQuery")) {
1842       LOG(ERROR) << "Receive error for GetMessagesViewsQuery: " << status;
1843     }
1844   }
1845 };
1846 
1847 class ReadMessagesContentsQuery final : public Td::ResultHandler {
1848   Promise<Unit> promise_;
1849 
1850  public:
ReadMessagesContentsQuery(Promise<Unit> && promise)1851   explicit ReadMessagesContentsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1852   }
1853 
send(vector<MessageId> && message_ids)1854   void send(vector<MessageId> &&message_ids) {
1855     send_query(G()->net_query_creator().create(
1856         telegram_api::messages_readMessageContents(MessagesManager::get_server_message_ids(message_ids))));
1857   }
1858 
on_result(BufferSlice packet)1859   void on_result(BufferSlice packet) final {
1860     auto result_ptr = fetch_result<telegram_api::messages_readMessageContents>(packet);
1861     if (result_ptr.is_error()) {
1862       return on_error(result_ptr.move_as_error());
1863     }
1864 
1865     auto affected_messages = result_ptr.move_as_ok();
1866     CHECK(affected_messages->get_id() == telegram_api::messages_affectedMessages::ID);
1867 
1868     if (affected_messages->pts_count_ > 0) {
1869       td_->updates_manager_->add_pending_pts_update(make_tl_object<dummyUpdate>(), affected_messages->pts_,
1870                                                     affected_messages->pts_count_, Time::now(), Promise<Unit>(),
1871                                                     "read messages content query");
1872     }
1873 
1874     promise_.set_value(Unit());
1875   }
1876 
on_error(Status status)1877   void on_error(Status status) final {
1878     if (!G()->is_expected_error(status)) {
1879       LOG(ERROR) << "Receive error for read message contents: " << status;
1880     }
1881     promise_.set_error(std::move(status));
1882   }
1883 };
1884 
1885 class ReadChannelMessagesContentsQuery final : public Td::ResultHandler {
1886   Promise<Unit> promise_;
1887   ChannelId channel_id_;
1888 
1889  public:
ReadChannelMessagesContentsQuery(Promise<Unit> && promise)1890   explicit ReadChannelMessagesContentsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1891   }
1892 
send(ChannelId channel_id,vector<MessageId> && message_ids)1893   void send(ChannelId channel_id, vector<MessageId> &&message_ids) {
1894     channel_id_ = channel_id;
1895 
1896     auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
1897     if (input_channel == nullptr) {
1898       LOG(ERROR) << "Have no input channel for " << channel_id;
1899       return on_error(Status::Error(500, "Can't read channel message contents"));
1900     }
1901 
1902     send_query(G()->net_query_creator().create(telegram_api::channels_readMessageContents(
1903         std::move(input_channel), MessagesManager::get_server_message_ids(message_ids))));
1904   }
1905 
on_result(BufferSlice packet)1906   void on_result(BufferSlice packet) final {
1907     auto result_ptr = fetch_result<telegram_api::channels_readMessageContents>(packet);
1908     if (result_ptr.is_error()) {
1909       return on_error(result_ptr.move_as_error());
1910     }
1911 
1912     bool result = result_ptr.ok();
1913     LOG_IF(ERROR, !result) << "Read channel messages contents failed";
1914 
1915     promise_.set_value(Unit());
1916   }
1917 
on_error(Status status)1918   void on_error(Status status) final {
1919     if (!td_->contacts_manager_->on_get_channel_error(channel_id_, status, "ReadChannelMessagesContentsQuery")) {
1920       LOG(ERROR) << "Receive error for read messages contents in " << channel_id_ << ": " << status;
1921     }
1922     promise_.set_error(std::move(status));
1923   }
1924 };
1925 
1926 class GetDialogMessageByDateQuery final : public Td::ResultHandler {
1927   Promise<Unit> promise_;
1928   DialogId dialog_id_;
1929   int32 date_;
1930   int64 random_id_;
1931 
1932  public:
GetDialogMessageByDateQuery(Promise<Unit> && promise)1933   explicit GetDialogMessageByDateQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1934   }
1935 
send(DialogId dialog_id,int32 date,int64 random_id)1936   void send(DialogId dialog_id, int32 date, int64 random_id) {
1937     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
1938     if (input_peer == nullptr) {
1939       return promise_.set_error(Status::Error(400, "Can't access the chat"));
1940     }
1941 
1942     dialog_id_ = dialog_id;
1943     date_ = date;
1944     random_id_ = random_id;
1945 
1946     send_query(G()->net_query_creator().create(
1947         telegram_api::messages_getHistory(std::move(input_peer), 0, date, -3, 5, 0, 0, 0)));
1948   }
1949 
on_result(BufferSlice packet)1950   void on_result(BufferSlice packet) final {
1951     auto result_ptr = fetch_result<telegram_api::messages_getHistory>(packet);
1952     if (result_ptr.is_error()) {
1953       return on_error(result_ptr.move_as_error());
1954     }
1955 
1956     auto info = td_->messages_manager_->get_messages_info(result_ptr.move_as_ok(), "GetDialogMessageByDateQuery");
1957     td_->messages_manager_->get_channel_difference_if_needed(
1958         dialog_id_, std::move(info),
1959         PromiseCreator::lambda([actor_id = td_->messages_manager_actor_.get(), dialog_id = dialog_id_, date = date_,
1960                                 random_id = random_id_,
1961                                 promise = std::move(promise_)](Result<MessagesManager::MessagesInfo> &&result) mutable {
1962           if (result.is_error()) {
1963             promise.set_error(result.move_as_error());
1964           } else {
1965             auto info = result.move_as_ok();
1966             send_closure(actor_id, &MessagesManager::on_get_dialog_message_by_date_success, dialog_id, date, random_id,
1967                          std::move(info.messages), std::move(promise));
1968           }
1969         }));
1970   }
1971 
on_error(Status status)1972   void on_error(Status status) final {
1973     if (!td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetDialogMessageByDateQuery")) {
1974       LOG(ERROR) << "Receive error for GetDialogMessageByDateQuery in " << dialog_id_ << ": " << status;
1975     }
1976     promise_.set_error(std::move(status));
1977     td_->messages_manager_->on_get_dialog_message_by_date_fail(random_id_);
1978   }
1979 };
1980 
1981 class GetHistoryQuery final : public Td::ResultHandler {
1982   Promise<Unit> promise_;
1983   DialogId dialog_id_;
1984   MessageId from_message_id_;
1985   MessageId old_last_new_message_id_;
1986   int32 offset_;
1987   int32 limit_;
1988   bool from_the_end_;
1989 
1990  public:
GetHistoryQuery(Promise<Unit> && promise)1991   explicit GetHistoryQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1992   }
1993 
send(DialogId dialog_id,MessageId from_message_id,MessageId old_last_new_message_id,int32 offset,int32 limit)1994   void send(DialogId dialog_id, MessageId from_message_id, MessageId old_last_new_message_id, int32 offset,
1995             int32 limit) {
1996     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
1997     if (input_peer == nullptr) {
1998       return promise_.set_error(Status::Error(400, "Can't access the chat"));
1999     }
2000     CHECK(offset < 0);
2001 
2002     dialog_id_ = dialog_id;
2003     from_message_id_ = from_message_id;
2004     old_last_new_message_id_ = old_last_new_message_id;
2005     offset_ = offset;
2006     limit_ = limit;
2007     from_the_end_ = false;
2008     send_query(G()->net_query_creator().create(telegram_api::messages_getHistory(
2009         std::move(input_peer), from_message_id.get_server_message_id().get(), 0, offset, limit, 0, 0, 0)));
2010   }
2011 
send_get_from_the_end(DialogId dialog_id,MessageId old_last_new_message_id,int32 limit)2012   void send_get_from_the_end(DialogId dialog_id, MessageId old_last_new_message_id, int32 limit) {
2013     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
2014     if (input_peer == nullptr) {
2015       return promise_.set_error(Status::Error(400, "Can't access the chat"));
2016     }
2017 
2018     dialog_id_ = dialog_id;
2019     old_last_new_message_id_ = old_last_new_message_id;
2020     offset_ = 0;
2021     limit_ = limit;
2022     from_the_end_ = true;
2023     send_query(G()->net_query_creator().create(
2024         telegram_api::messages_getHistory(std::move(input_peer), 0, 0, 0, limit, 0, 0, 0)));
2025   }
2026 
on_result(BufferSlice packet)2027   void on_result(BufferSlice packet) final {
2028     auto result_ptr = fetch_result<telegram_api::messages_getHistory>(packet);
2029     if (result_ptr.is_error()) {
2030       return on_error(result_ptr.move_as_error());
2031     }
2032 
2033     auto info = td_->messages_manager_->get_messages_info(result_ptr.move_as_ok(), "GetHistoryQuery");
2034     td_->messages_manager_->get_channel_difference_if_needed(
2035         dialog_id_, std::move(info),
2036         PromiseCreator::lambda([actor_id = td_->messages_manager_actor_.get(), dialog_id = dialog_id_,
2037                                 from_message_id = from_message_id_, old_last_new_message_id = old_last_new_message_id_,
2038                                 offset = offset_, limit = limit_, from_the_end = from_the_end_,
2039                                 promise = std::move(promise_)](Result<MessagesManager::MessagesInfo> &&result) mutable {
2040           if (result.is_error()) {
2041             promise.set_error(result.move_as_error());
2042           } else {
2043             auto info = result.move_as_ok();
2044             // TODO use info.total_count, info.pts
2045             send_closure(actor_id, &MessagesManager::on_get_history, dialog_id, from_message_id,
2046                          old_last_new_message_id, offset, limit, from_the_end, std::move(info.messages),
2047                          std::move(promise));
2048           }
2049         }));
2050   }
2051 
on_error(Status status)2052   void on_error(Status status) final {
2053     if (!td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetHistoryQuery")) {
2054       LOG(ERROR) << "Receive error for GetHistoryQuery in " << dialog_id_ << ": " << status;
2055     }
2056     promise_.set_error(std::move(status));
2057   }
2058 };
2059 
2060 class ReadHistoryQuery final : public Td::ResultHandler {
2061   Promise<Unit> promise_;
2062   DialogId dialog_id_;
2063 
2064  public:
ReadHistoryQuery(Promise<Unit> && promise)2065   explicit ReadHistoryQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2066   }
2067 
send(DialogId dialog_id,MessageId max_message_id)2068   void send(DialogId dialog_id, MessageId max_message_id) {
2069     dialog_id_ = dialog_id;
2070     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
2071     CHECK(input_peer != nullptr);
2072     send_query(G()->net_query_creator().create(
2073         telegram_api::messages_readHistory(std::move(input_peer), max_message_id.get_server_message_id().get())));
2074   }
2075 
on_result(BufferSlice packet)2076   void on_result(BufferSlice packet) final {
2077     auto result_ptr = fetch_result<telegram_api::messages_readHistory>(packet);
2078     if (result_ptr.is_error()) {
2079       return on_error(result_ptr.move_as_error());
2080     }
2081 
2082     auto affected_messages = result_ptr.move_as_ok();
2083     CHECK(affected_messages->get_id() == telegram_api::messages_affectedMessages::ID);
2084     LOG(INFO) << "Receive result for ReadHistoryQuery: " << to_string(affected_messages);
2085 
2086     if (affected_messages->pts_count_ > 0) {
2087       td_->updates_manager_->add_pending_pts_update(make_tl_object<dummyUpdate>(), affected_messages->pts_,
2088                                                     affected_messages->pts_count_, Time::now(), Promise<Unit>(),
2089                                                     "read history query");
2090     }
2091 
2092     promise_.set_value(Unit());
2093   }
2094 
on_error(Status status)2095   void on_error(Status status) final {
2096     if (!td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "ReadHistoryQuery")) {
2097       LOG(ERROR) << "Receive error for ReadHistoryQuery: " << status;
2098     }
2099     promise_.set_error(std::move(status));
2100   }
2101 };
2102 
2103 class ReadChannelHistoryQuery final : public Td::ResultHandler {
2104   Promise<Unit> promise_;
2105   ChannelId channel_id_;
2106 
2107  public:
ReadChannelHistoryQuery(Promise<Unit> && promise)2108   explicit ReadChannelHistoryQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2109   }
2110 
send(ChannelId channel_id,MessageId max_message_id)2111   void send(ChannelId channel_id, MessageId max_message_id) {
2112     channel_id_ = channel_id;
2113     auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
2114     CHECK(input_channel != nullptr);
2115 
2116     send_query(G()->net_query_creator().create(
2117         telegram_api::channels_readHistory(std::move(input_channel), max_message_id.get_server_message_id().get())));
2118   }
2119 
on_result(BufferSlice packet)2120   void on_result(BufferSlice packet) final {
2121     auto result_ptr = fetch_result<telegram_api::channels_readHistory>(packet);
2122     if (result_ptr.is_error()) {
2123       return on_error(result_ptr.move_as_error());
2124     }
2125 
2126     promise_.set_value(Unit());
2127   }
2128 
on_error(Status status)2129   void on_error(Status status) final {
2130     if (!td_->contacts_manager_->on_get_channel_error(channel_id_, status, "ReadChannelHistoryQuery")) {
2131       LOG(ERROR) << "Receive error for ReadChannelHistoryQuery: " << status;
2132     }
2133     promise_.set_error(std::move(status));
2134   }
2135 };
2136 
2137 class ReadDiscussionQuery final : public Td::ResultHandler {
2138   Promise<Unit> promise_;
2139   DialogId dialog_id_;
2140 
2141  public:
ReadDiscussionQuery(Promise<Unit> && promise)2142   explicit ReadDiscussionQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2143   }
2144 
send(DialogId dialog_id,MessageId top_thread_message_id,MessageId max_message_id)2145   void send(DialogId dialog_id, MessageId top_thread_message_id, MessageId max_message_id) {
2146     dialog_id_ = dialog_id;
2147     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
2148     CHECK(input_peer != nullptr);
2149     send_query(G()->net_query_creator().create(telegram_api::messages_readDiscussion(
2150         std::move(input_peer), top_thread_message_id.get_server_message_id().get(),
2151         max_message_id.get_server_message_id().get())));
2152   }
2153 
on_result(BufferSlice packet)2154   void on_result(BufferSlice packet) final {
2155     auto result_ptr = fetch_result<telegram_api::messages_readDiscussion>(packet);
2156     if (result_ptr.is_error()) {
2157       return on_error(result_ptr.move_as_error());
2158     }
2159 
2160     promise_.set_value(Unit());
2161   }
2162 
on_error(Status status)2163   void on_error(Status status) final {
2164     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "ReadDiscussionQuery");
2165     promise_.set_error(std::move(status));
2166   }
2167 };
2168 
2169 class GetSearchResultCalendarQuery final : public Td::ResultHandler {
2170   Promise<Unit> promise_;
2171   DialogId dialog_id_;
2172   MessageId from_message_id_;
2173   MessageSearchFilter filter_;
2174   int64 random_id_;
2175 
2176  public:
GetSearchResultCalendarQuery(Promise<Unit> && promise)2177   explicit GetSearchResultCalendarQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2178   }
2179 
send(DialogId dialog_id,MessageId from_message_id,MessageSearchFilter filter,int64 random_id)2180   void send(DialogId dialog_id, MessageId from_message_id, MessageSearchFilter filter, int64 random_id) {
2181     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
2182     CHECK(input_peer != nullptr);
2183 
2184     dialog_id_ = dialog_id;
2185     from_message_id_ = from_message_id;
2186     filter_ = filter;
2187     random_id_ = random_id;
2188 
2189     send_query(G()->net_query_creator().create(telegram_api::messages_getSearchResultsCalendar(
2190         std::move(input_peer), get_input_messages_filter(filter), from_message_id.get_server_message_id().get(), 0)));
2191   }
2192 
on_result(BufferSlice packet)2193   void on_result(BufferSlice packet) final {
2194     auto result_ptr = fetch_result<telegram_api::messages_getSearchResultsCalendar>(packet);
2195     if (result_ptr.is_error()) {
2196       return on_error(result_ptr.move_as_error());
2197     }
2198 
2199     auto result = result_ptr.move_as_ok();
2200     LOG(INFO) << "Receive result for GetSearchResultCalendarQuery: " << to_string(result);
2201     td_->contacts_manager_->on_get_users(std::move(result->users_), "GetSearchResultCalendarQuery");
2202     td_->contacts_manager_->on_get_chats(std::move(result->chats_), "GetSearchResultCalendarQuery");
2203 
2204     MessagesManager::MessagesInfo info;
2205     info.messages = std::move(result->messages_);
2206     info.total_count = result->count_;
2207     info.is_channel_messages = dialog_id_.get_type() == DialogType::Channel;
2208 
2209     td_->messages_manager_->get_channel_difference_if_needed(
2210         dialog_id_, std::move(info),
2211         PromiseCreator::lambda([actor_id = td_->messages_manager_actor_.get(), dialog_id = dialog_id_,
2212                                 from_message_id = from_message_id_, filter = filter_, random_id = random_id_,
2213                                 periods = std::move(result->periods_),
2214                                 promise = std::move(promise_)](Result<MessagesManager::MessagesInfo> &&result) mutable {
2215           if (result.is_error()) {
2216             promise.set_error(result.move_as_error());
2217           } else {
2218             auto info = result.move_as_ok();
2219             send_closure(actor_id, &MessagesManager::on_get_message_search_result_calendar, dialog_id, from_message_id,
2220                          filter, random_id, info.total_count, std::move(info.messages), std::move(periods),
2221                          std::move(promise));
2222           }
2223         }));
2224   }
2225 
on_error(Status status)2226   void on_error(Status status) final {
2227     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetSearchResultCalendarQuery");
2228     td_->messages_manager_->on_failed_get_message_search_result_calendar(dialog_id_, random_id_);
2229     promise_.set_error(std::move(status));
2230   }
2231 };
2232 
2233 class SearchMessagesQuery final : public Td::ResultHandler {
2234   Promise<Unit> promise_;
2235   DialogId dialog_id_;
2236   string query_;
2237   DialogId sender_dialog_id_;
2238   MessageId from_message_id_;
2239   int32 offset_;
2240   int32 limit_;
2241   MessageSearchFilter filter_;
2242   MessageId top_thread_message_id_;
2243   int64 random_id_;
2244   bool handle_errors_ = true;
2245 
2246  public:
SearchMessagesQuery(Promise<Unit> && promise)2247   explicit SearchMessagesQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2248   }
2249 
send(DialogId dialog_id,const string & query,DialogId sender_dialog_id,MessageId from_message_id,int32 offset,int32 limit,MessageSearchFilter filter,MessageId top_thread_message_id,int64 random_id)2250   void send(DialogId dialog_id, const string &query, DialogId sender_dialog_id, MessageId from_message_id, int32 offset,
2251             int32 limit, MessageSearchFilter filter, MessageId top_thread_message_id, int64 random_id) {
2252     auto input_peer = dialog_id.is_valid() ? td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read)
2253                                            : make_tl_object<telegram_api::inputPeerEmpty>();
2254     CHECK(input_peer != nullptr);
2255 
2256     dialog_id_ = dialog_id;
2257     query_ = query;
2258     sender_dialog_id_ = sender_dialog_id;
2259     from_message_id_ = from_message_id;
2260     offset_ = offset;
2261     limit_ = limit;
2262     filter_ = filter;
2263     top_thread_message_id_ = top_thread_message_id;
2264     random_id_ = random_id;
2265 
2266     if (filter == MessageSearchFilter::UnreadMention) {
2267       send_query(G()->net_query_creator().create(
2268           telegram_api::messages_getUnreadMentions(std::move(input_peer), from_message_id.get_server_message_id().get(),
2269                                                    offset, limit, std::numeric_limits<int32>::max(), 0)));
2270     } else if (top_thread_message_id.is_valid() && query.empty() && !sender_dialog_id.is_valid() &&
2271                filter == MessageSearchFilter::Empty) {
2272       handle_errors_ = dialog_id.get_type() != DialogType::Channel ||
2273                        td_->contacts_manager_->get_channel_type(dialog_id.get_channel_id()) !=
2274                            ContactsManager::ChannelType::Broadcast;
2275       send_query(G()->net_query_creator().create(telegram_api::messages_getReplies(
2276           std::move(input_peer), top_thread_message_id.get_server_message_id().get(),
2277           from_message_id.get_server_message_id().get(), 0, offset, limit, std::numeric_limits<int32>::max(), 0, 0)));
2278     } else {
2279       int32 flags = 0;
2280       tl_object_ptr<telegram_api::InputPeer> sender_input_peer;
2281       if (sender_dialog_id.is_valid()) {
2282         flags |= telegram_api::messages_search::FROM_ID_MASK;
2283         sender_input_peer = td_->messages_manager_->get_input_peer(sender_dialog_id, AccessRights::Know);
2284         CHECK(sender_input_peer != nullptr);
2285       }
2286       if (top_thread_message_id.is_valid()) {
2287         flags |= telegram_api::messages_search::TOP_MSG_ID_MASK;
2288       }
2289 
2290       send_query(G()->net_query_creator().create(telegram_api::messages_search(
2291           flags, std::move(input_peer), query, std::move(sender_input_peer),
2292           top_thread_message_id.get_server_message_id().get(), get_input_messages_filter(filter), 0,
2293           std::numeric_limits<int32>::max(), from_message_id.get_server_message_id().get(), offset, limit,
2294           std::numeric_limits<int32>::max(), 0, 0)));
2295     }
2296   }
2297 
on_result(BufferSlice packet)2298   void on_result(BufferSlice packet) final {
2299     static_assert(std::is_same<telegram_api::messages_getUnreadMentions::ReturnType,
2300                                telegram_api::messages_search::ReturnType>::value,
2301                   "");
2302     static_assert(
2303         std::is_same<telegram_api::messages_getReplies::ReturnType, telegram_api::messages_search::ReturnType>::value,
2304         "");
2305     auto result_ptr = fetch_result<telegram_api::messages_search>(packet);
2306     if (result_ptr.is_error()) {
2307       return on_error(result_ptr.move_as_error());
2308     }
2309 
2310     auto info = td_->messages_manager_->get_messages_info(result_ptr.move_as_ok(), "SearchMessagesQuery");
2311     td_->messages_manager_->get_channel_difference_if_needed(
2312         dialog_id_, std::move(info),
2313         PromiseCreator::lambda([actor_id = td_->messages_manager_actor_.get(), dialog_id = dialog_id_,
2314                                 query = std::move(query_), sender_dialog_id = sender_dialog_id_,
2315                                 from_message_id = from_message_id_, offset = offset_, limit = limit_, filter = filter_,
2316                                 top_thread_message_id = top_thread_message_id_, random_id = random_id_,
2317                                 promise = std::move(promise_)](Result<MessagesManager::MessagesInfo> &&result) mutable {
2318           if (result.is_error()) {
2319             promise.set_error(result.move_as_error());
2320           } else {
2321             auto info = result.move_as_ok();
2322             send_closure(actor_id, &MessagesManager::on_get_dialog_messages_search_result, dialog_id, query,
2323                          sender_dialog_id, from_message_id, offset, limit, filter, top_thread_message_id, random_id,
2324                          info.total_count, std::move(info.messages), std::move(promise));
2325           }
2326         }));
2327   }
2328 
on_error(Status status)2329   void on_error(Status status) final {
2330     if (handle_errors_) {
2331       td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "SearchMessagesQuery");
2332     }
2333     td_->messages_manager_->on_failed_dialog_messages_search(dialog_id_, random_id_);
2334     promise_.set_error(std::move(status));
2335   }
2336 };
2337 
2338 class GetSearchResultPositionsQuery final : public Td::ResultHandler {
2339   Promise<td_api::object_ptr<td_api::messagePositions>> promise_;
2340   DialogId dialog_id_;
2341   MessageSearchFilter filter_;
2342 
2343  public:
GetSearchResultPositionsQuery(Promise<td_api::object_ptr<td_api::messagePositions>> && promise)2344   explicit GetSearchResultPositionsQuery(Promise<td_api::object_ptr<td_api::messagePositions>> &&promise)
2345       : promise_(std::move(promise)) {
2346   }
2347 
send(DialogId dialog_id,MessageSearchFilter filter,MessageId from_message_id,int32 limit)2348   void send(DialogId dialog_id, MessageSearchFilter filter, MessageId from_message_id, int32 limit) {
2349     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
2350     if (input_peer == nullptr) {
2351       return promise_.set_error(Status::Error(400, "Can't access the chat"));
2352     }
2353     dialog_id_ = dialog_id;
2354     filter_ = filter;
2355 
2356     send_query(G()->net_query_creator().create(
2357         telegram_api::messages_getSearchResultsPositions(std::move(input_peer), get_input_messages_filter(filter),
2358                                                          from_message_id.get_server_message_id().get(), limit)));
2359   }
2360 
on_result(BufferSlice packet)2361   void on_result(BufferSlice packet) final {
2362     auto result_ptr = fetch_result<telegram_api::messages_getSearchResultsPositions>(packet);
2363     if (result_ptr.is_error()) {
2364       return on_error(result_ptr.move_as_error());
2365     }
2366 
2367     td_->messages_manager_->on_get_dialog_sparse_message_positions(dialog_id_, filter_, result_ptr.move_as_ok(),
2368                                                                    std::move(promise_));
2369   }
2370 
on_error(Status status)2371   void on_error(Status status) final {
2372     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetSearchResultPositionsQuery");
2373     promise_.set_error(std::move(status));
2374   }
2375 };
2376 
2377 class GetSearchCountersQuery final : public Td::ResultHandler {
2378   Promise<int32> promise_;
2379   DialogId dialog_id_;
2380   MessageSearchFilter filter_;
2381 
2382  public:
GetSearchCountersQuery(Promise<int32> && promise)2383   explicit GetSearchCountersQuery(Promise<int32> &&promise) : promise_(std::move(promise)) {
2384   }
2385 
send(DialogId dialog_id,MessageSearchFilter filter)2386   void send(DialogId dialog_id, MessageSearchFilter filter) {
2387     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
2388     if (input_peer == nullptr) {
2389       return promise_.set_error(Status::Error(400, "Can't access the chat"));
2390     }
2391 
2392     dialog_id_ = dialog_id;
2393     filter_ = filter;
2394 
2395     CHECK(filter != MessageSearchFilter::Empty);
2396     CHECK(filter != MessageSearchFilter::UnreadMention);
2397     CHECK(filter != MessageSearchFilter::FailedToSend);
2398     vector<telegram_api::object_ptr<telegram_api::MessagesFilter>> filters;
2399     filters.push_back(get_input_messages_filter(filter));
2400     send_query(G()->net_query_creator().create(
2401         telegram_api::messages_getSearchCounters(std::move(input_peer), std::move(filters))));
2402   }
2403 
on_result(BufferSlice packet)2404   void on_result(BufferSlice packet) final {
2405     auto result_ptr = fetch_result<telegram_api::messages_getSearchCounters>(packet);
2406     if (result_ptr.is_error()) {
2407       return on_error(result_ptr.move_as_error());
2408     }
2409 
2410     auto result = result_ptr.move_as_ok();
2411     if (result.size() != 1 || result[0]->filter_->get_id() != get_input_messages_filter(filter_)->get_id()) {
2412       LOG(ERROR) << "Receive unexpected response for get message count in " << dialog_id_ << " with filter " << filter_
2413                  << ": " << to_string(result);
2414       return on_error(Status::Error(500, "Receive wrong response"));
2415     }
2416 
2417     td_->messages_manager_->on_get_dialog_message_count(dialog_id_, filter_, result[0]->count_, std::move(promise_));
2418   }
2419 
on_error(Status status)2420   void on_error(Status status) final {
2421     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetSearchCountersQuery");
2422     promise_.set_error(std::move(status));
2423   }
2424 };
2425 
2426 class SearchMessagesGlobalQuery final : public Td::ResultHandler {
2427   Promise<Unit> promise_;
2428   string query_;
2429   int32 offset_date_;
2430   DialogId offset_dialog_id_;
2431   MessageId offset_message_id_;
2432   int32 limit_;
2433   MessageSearchFilter filter_;
2434   int32 min_date_;
2435   int32 max_date_;
2436   int64 random_id_;
2437 
2438  public:
SearchMessagesGlobalQuery(Promise<Unit> && promise)2439   explicit SearchMessagesGlobalQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2440   }
2441 
send(FolderId folder_id,bool ignore_folder_id,const string & query,int32 offset_date,DialogId offset_dialog_id,MessageId offset_message_id,int32 limit,MessageSearchFilter filter,int32 min_date,int32 max_date,int64 random_id)2442   void send(FolderId folder_id, bool ignore_folder_id, const string &query, int32 offset_date,
2443             DialogId offset_dialog_id, MessageId offset_message_id, int32 limit, MessageSearchFilter filter,
2444             int32 min_date, int32 max_date, int64 random_id) {
2445     query_ = query;
2446     offset_date_ = offset_date;
2447     offset_dialog_id_ = offset_dialog_id;
2448     offset_message_id_ = offset_message_id;
2449     limit_ = limit;
2450     random_id_ = random_id;
2451     filter_ = filter;
2452     min_date_ = min_date;
2453     max_date_ = max_date;
2454 
2455     auto input_peer = MessagesManager::get_input_peer_force(offset_dialog_id);
2456     CHECK(input_peer != nullptr);
2457 
2458     int32 flags = 0;
2459     if (!ignore_folder_id) {
2460       flags |= telegram_api::messages_searchGlobal::FOLDER_ID_MASK;
2461     }
2462     send_query(G()->net_query_creator().create(telegram_api::messages_searchGlobal(
2463         flags, folder_id.get(), query, get_input_messages_filter(filter), min_date_, max_date_, offset_date_,
2464         std::move(input_peer), offset_message_id.get_server_message_id().get(), limit)));
2465   }
2466 
on_result(BufferSlice packet)2467   void on_result(BufferSlice packet) final {
2468     auto result_ptr = fetch_result<telegram_api::messages_searchGlobal>(packet);
2469     if (result_ptr.is_error()) {
2470       return on_error(result_ptr.move_as_error());
2471     }
2472 
2473     auto info = td_->messages_manager_->get_messages_info(result_ptr.move_as_ok(), "SearchMessagesGlobalQuery");
2474     td_->messages_manager_->get_channel_differences_if_needed(
2475         std::move(info),
2476         PromiseCreator::lambda([actor_id = td_->messages_manager_actor_.get(), query = std::move(query_),
2477                                 offset_date = offset_date_, offset_dialog_id = offset_dialog_id_,
2478                                 offset_message_id = offset_message_id_, limit = limit_, filter = std::move(filter_),
2479                                 min_date = min_date_, max_date = max_date_, random_id = random_id_,
2480                                 promise = std::move(promise_)](Result<MessagesManager::MessagesInfo> &&result) mutable {
2481           if (result.is_error()) {
2482             promise.set_error(result.move_as_error());
2483           } else {
2484             auto info = result.move_as_ok();
2485             send_closure(actor_id, &MessagesManager::on_get_messages_search_result, query, offset_date,
2486                          offset_dialog_id, offset_message_id, limit, filter, min_date, max_date, random_id,
2487                          info.total_count, std::move(info.messages), std::move(promise));
2488           }
2489         }));
2490   }
2491 
on_error(Status status)2492   void on_error(Status status) final {
2493     td_->messages_manager_->on_failed_messages_search(random_id_);
2494     promise_.set_error(std::move(status));
2495   }
2496 };
2497 
2498 class GetAllScheduledMessagesQuery final : public Td::ResultHandler {
2499   Promise<Unit> promise_;
2500   DialogId dialog_id_;
2501   uint32 generation_;
2502 
2503  public:
GetAllScheduledMessagesQuery(Promise<Unit> && promise)2504   explicit GetAllScheduledMessagesQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2505   }
2506 
send(DialogId dialog_id,int64 hash,uint32 generation)2507   void send(DialogId dialog_id, int64 hash, uint32 generation) {
2508     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
2509     CHECK(input_peer != nullptr);
2510 
2511     dialog_id_ = dialog_id;
2512     generation_ = generation;
2513 
2514     send_query(
2515         G()->net_query_creator().create(telegram_api::messages_getScheduledHistory(std::move(input_peer), hash)));
2516   }
2517 
on_result(BufferSlice packet)2518   void on_result(BufferSlice packet) final {
2519     auto result_ptr = fetch_result<telegram_api::messages_getScheduledHistory>(packet);
2520     if (result_ptr.is_error()) {
2521       return on_error(result_ptr.move_as_error());
2522     }
2523 
2524     if (result_ptr.ok()->get_id() == telegram_api::messages_messagesNotModified::ID) {
2525       td_->messages_manager_->on_get_scheduled_server_messages(dialog_id_, generation_, Auto(), true);
2526     } else {
2527       auto info = td_->messages_manager_->get_messages_info(result_ptr.move_as_ok(), "GetAllScheduledMessagesQuery");
2528       td_->messages_manager_->on_get_scheduled_server_messages(dialog_id_, generation_, std::move(info.messages),
2529                                                                false);
2530     }
2531 
2532     promise_.set_value(Unit());
2533   }
2534 
on_error(Status status)2535   void on_error(Status status) final {
2536     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetAllScheduledMessagesQuery");
2537     promise_.set_error(std::move(status));
2538   }
2539 };
2540 
2541 class GetRecentLocationsQuery final : public Td::ResultHandler {
2542   Promise<td_api::object_ptr<td_api::messages>> promise_;
2543   DialogId dialog_id_;
2544   int32 limit_;
2545 
2546  public:
GetRecentLocationsQuery(Promise<td_api::object_ptr<td_api::messages>> && promise)2547   explicit GetRecentLocationsQuery(Promise<td_api::object_ptr<td_api::messages>> &&promise)
2548       : promise_(std::move(promise)) {
2549   }
2550 
send(DialogId dialog_id,int32 limit)2551   void send(DialogId dialog_id, int32 limit) {
2552     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
2553     if (input_peer == nullptr) {
2554       return on_error(Status::Error(400, "Have no info about the chat"));
2555     }
2556 
2557     dialog_id_ = dialog_id;
2558     limit_ = limit;
2559 
2560     send_query(
2561         G()->net_query_creator().create(telegram_api::messages_getRecentLocations(std::move(input_peer), limit, 0)));
2562   }
2563 
on_result(BufferSlice packet)2564   void on_result(BufferSlice packet) final {
2565     auto result_ptr = fetch_result<telegram_api::messages_getRecentLocations>(packet);
2566     if (result_ptr.is_error()) {
2567       return on_error(result_ptr.move_as_error());
2568     }
2569 
2570     auto info = td_->messages_manager_->get_messages_info(result_ptr.move_as_ok(), "GetRecentLocationsQuery");
2571     td_->messages_manager_->get_channel_difference_if_needed(
2572         dialog_id_, std::move(info),
2573         PromiseCreator::lambda([actor_id = td_->messages_manager_actor_.get(), dialog_id = dialog_id_, limit = limit_,
2574                                 promise = std::move(promise_)](Result<MessagesManager::MessagesInfo> &&result) mutable {
2575           if (result.is_error()) {
2576             promise.set_error(result.move_as_error());
2577           } else {
2578             auto info = result.move_as_ok();
2579             send_closure(actor_id, &MessagesManager::on_get_recent_locations, dialog_id, limit, info.total_count,
2580                          std::move(info.messages), std::move(promise));
2581           }
2582         }));
2583   }
2584 
on_error(Status status)2585   void on_error(Status status) final {
2586     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetRecentLocationsQuery");
2587     promise_.set_error(std::move(status));
2588   }
2589 };
2590 
2591 class GetMessagePublicForwardsQuery final : public Td::ResultHandler {
2592   Promise<td_api::object_ptr<td_api::foundMessages>> promise_;
2593   DialogId dialog_id_;
2594   int32 limit_;
2595 
2596  public:
GetMessagePublicForwardsQuery(Promise<td_api::object_ptr<td_api::foundMessages>> && promise)2597   explicit GetMessagePublicForwardsQuery(Promise<td_api::object_ptr<td_api::foundMessages>> &&promise)
2598       : promise_(std::move(promise)) {
2599   }
2600 
send(DcId dc_id,FullMessageId full_message_id,int32 offset_date,DialogId offset_dialog_id,ServerMessageId offset_message_id,int32 limit)2601   void send(DcId dc_id, FullMessageId full_message_id, int32 offset_date, DialogId offset_dialog_id,
2602             ServerMessageId offset_message_id, int32 limit) {
2603     dialog_id_ = full_message_id.get_dialog_id();
2604     limit_ = limit;
2605 
2606     auto input_peer = MessagesManager::get_input_peer_force(offset_dialog_id);
2607     CHECK(input_peer != nullptr);
2608 
2609     send_query(
2610         G()->net_query_creator().create(telegram_api::stats_getMessagePublicForwards(
2611                                             td_->contacts_manager_->get_input_channel(dialog_id_.get_channel_id()),
2612                                             full_message_id.get_message_id().get_server_message_id().get(), offset_date,
2613                                             std::move(input_peer), offset_message_id.get(), limit),
2614                                         dc_id));
2615   }
2616 
on_result(BufferSlice packet)2617   void on_result(BufferSlice packet) final {
2618     auto result_ptr = fetch_result<telegram_api::stats_getMessagePublicForwards>(packet);
2619     if (result_ptr.is_error()) {
2620       return on_error(result_ptr.move_as_error());
2621     }
2622 
2623     auto info = td_->messages_manager_->get_messages_info(result_ptr.move_as_ok(), "GetMessagePublicForwardsQuery");
2624     td_->messages_manager_->get_channel_differences_if_needed(
2625         std::move(info),
2626         PromiseCreator::lambda([actor_id = td_->messages_manager_actor_.get(),
2627                                 promise = std::move(promise_)](Result<MessagesManager::MessagesInfo> &&result) mutable {
2628           if (result.is_error()) {
2629             promise.set_error(result.move_as_error());
2630           } else {
2631             auto info = result.move_as_ok();
2632             send_closure(actor_id, &MessagesManager::on_get_message_public_forwards, info.total_count,
2633                          std::move(info.messages), std::move(promise));
2634           }
2635         }));
2636   }
2637 
on_error(Status status)2638   void on_error(Status status) final {
2639     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetMessagePublicForwardsQuery");
2640     promise_.set_error(std::move(status));
2641   }
2642 };
2643 
2644 class HidePromoDataQuery final : public Td::ResultHandler {
2645   DialogId dialog_id_;
2646 
2647  public:
send(DialogId dialog_id)2648   void send(DialogId dialog_id) {
2649     dialog_id_ = dialog_id;
2650     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
2651     CHECK(input_peer != nullptr);
2652     send_query(G()->net_query_creator().create(telegram_api::help_hidePromoData(std::move(input_peer))));
2653   }
2654 
on_result(BufferSlice packet)2655   void on_result(BufferSlice packet) final {
2656     auto result_ptr = fetch_result<telegram_api::help_hidePromoData>(packet);
2657     if (result_ptr.is_error()) {
2658       return on_error(result_ptr.move_as_error());
2659     }
2660 
2661     // we are not interested in the result
2662   }
2663 
on_error(Status status)2664   void on_error(Status status) final {
2665     if (!td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "HidePromoDataQuery")) {
2666       LOG(ERROR) << "Receive error for sponsored chat hiding: " << status;
2667     }
2668   }
2669 };
2670 
2671 class DeleteHistoryQuery final : public Td::ResultHandler {
2672   Promise<AffectedHistory> promise_;
2673   DialogId dialog_id_;
2674 
2675  public:
DeleteHistoryQuery(Promise<AffectedHistory> && promise)2676   explicit DeleteHistoryQuery(Promise<AffectedHistory> &&promise) : promise_(std::move(promise)) {
2677   }
2678 
send(DialogId dialog_id,MessageId max_message_id,bool remove_from_dialog_list,bool revoke)2679   void send(DialogId dialog_id, MessageId max_message_id, bool remove_from_dialog_list, bool revoke) {
2680     dialog_id_ = dialog_id;
2681 
2682     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id_, AccessRights::Read);
2683     if (input_peer == nullptr) {
2684       return promise_.set_error(Status::Error(400, "Chat is not accessible"));
2685     }
2686 
2687     int32 flags = 0;
2688     if (!remove_from_dialog_list) {
2689       flags |= telegram_api::messages_deleteHistory::JUST_CLEAR_MASK;
2690     }
2691     if (revoke) {
2692       flags |= telegram_api::messages_deleteHistory::REVOKE_MASK;
2693     }
2694 
2695     send_query(G()->net_query_creator().create(
2696         telegram_api::messages_deleteHistory(flags, false /*ignored*/, false /*ignored*/, std::move(input_peer),
2697                                              max_message_id.get_server_message_id().get(), 0, 0)));
2698   }
2699 
on_result(BufferSlice packet)2700   void on_result(BufferSlice packet) final {
2701     auto result_ptr = fetch_result<telegram_api::messages_deleteHistory>(packet);
2702     if (result_ptr.is_error()) {
2703       return on_error(result_ptr.move_as_error());
2704     }
2705 
2706     promise_.set_value(AffectedHistory(result_ptr.move_as_ok()));
2707   }
2708 
on_error(Status status)2709   void on_error(Status status) final {
2710     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "DeleteHistoryQuery");
2711     promise_.set_error(std::move(status));
2712   }
2713 };
2714 
2715 class DeleteChannelHistoryQuery final : public Td::ResultHandler {
2716   Promise<Unit> promise_;
2717   ChannelId channel_id_;
2718   MessageId max_message_id_;
2719   bool allow_error_;
2720 
2721  public:
DeleteChannelHistoryQuery(Promise<Unit> && promise)2722   explicit DeleteChannelHistoryQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2723   }
2724 
send(ChannelId channel_id,MessageId max_message_id,bool allow_error)2725   void send(ChannelId channel_id, MessageId max_message_id, bool allow_error) {
2726     channel_id_ = channel_id;
2727     max_message_id_ = max_message_id;
2728     allow_error_ = allow_error;
2729     auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
2730     CHECK(input_channel != nullptr);
2731 
2732     send_query(G()->net_query_creator().create(
2733         telegram_api::channels_deleteHistory(std::move(input_channel), max_message_id.get_server_message_id().get())));
2734   }
2735 
on_result(BufferSlice packet)2736   void on_result(BufferSlice packet) final {
2737     auto result_ptr = fetch_result<telegram_api::channels_deleteHistory>(packet);
2738     if (result_ptr.is_error()) {
2739       return on_error(result_ptr.move_as_error());
2740     }
2741 
2742     bool result = result_ptr.ok();
2743     LOG_IF(ERROR, !allow_error_ && !result)
2744         << "Delete history in " << channel_id_ << " up to " << max_message_id_ << " failed";
2745 
2746     promise_.set_value(Unit());
2747   }
2748 
on_error(Status status)2749   void on_error(Status status) final {
2750     if (!td_->contacts_manager_->on_get_channel_error(channel_id_, status, "DeleteChannelHistoryQuery")) {
2751       LOG(ERROR) << "Receive error for DeleteChannelHistoryQuery: " << status;
2752     }
2753     promise_.set_error(std::move(status));
2754   }
2755 };
2756 
2757 class DeleteMessagesByDateQuery final : public Td::ResultHandler {
2758   Promise<AffectedHistory> promise_;
2759   DialogId dialog_id_;
2760 
2761  public:
DeleteMessagesByDateQuery(Promise<AffectedHistory> && promise)2762   explicit DeleteMessagesByDateQuery(Promise<AffectedHistory> &&promise) : promise_(std::move(promise)) {
2763   }
2764 
send(DialogId dialog_id,int32 min_date,int32 max_date,bool revoke)2765   void send(DialogId dialog_id, int32 min_date, int32 max_date, bool revoke) {
2766     dialog_id_ = dialog_id;
2767 
2768     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id_, AccessRights::Read);
2769     if (input_peer == nullptr) {
2770       return promise_.set_error(Status::Error(400, "Chat is not accessible"));
2771     }
2772 
2773     int32 flags = telegram_api::messages_deleteHistory::JUST_CLEAR_MASK |
2774                   telegram_api::messages_deleteHistory::MIN_DATE_MASK |
2775                   telegram_api::messages_deleteHistory::MAX_DATE_MASK;
2776     if (revoke) {
2777       flags |= telegram_api::messages_deleteHistory::REVOKE_MASK;
2778     }
2779 
2780     send_query(G()->net_query_creator().create(telegram_api::messages_deleteHistory(
2781         flags, false /*ignored*/, false /*ignored*/, std::move(input_peer), 0, min_date, max_date)));
2782   }
2783 
on_result(BufferSlice packet)2784   void on_result(BufferSlice packet) final {
2785     auto result_ptr = fetch_result<telegram_api::messages_deleteHistory>(packet);
2786     if (result_ptr.is_error()) {
2787       return on_error(result_ptr.move_as_error());
2788     }
2789 
2790     promise_.set_value(AffectedHistory(result_ptr.move_as_ok()));
2791   }
2792 
on_error(Status status)2793   void on_error(Status status) final {
2794     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "DeleteMessagesByDateQuery");
2795     promise_.set_error(std::move(status));
2796   }
2797 };
2798 
2799 class DeletePhoneCallHistoryQuery final : public Td::ResultHandler {
2800   Promise<AffectedHistory> promise_;
2801 
2802  public:
DeletePhoneCallHistoryQuery(Promise<AffectedHistory> && promise)2803   explicit DeletePhoneCallHistoryQuery(Promise<AffectedHistory> &&promise) : promise_(std::move(promise)) {
2804   }
2805 
send(bool revoke)2806   void send(bool revoke) {
2807     int32 flags = 0;
2808     if (revoke) {
2809       flags |= telegram_api::messages_deletePhoneCallHistory::REVOKE_MASK;
2810     }
2811     send_query(
2812         G()->net_query_creator().create(telegram_api::messages_deletePhoneCallHistory(flags, false /*ignored*/)));
2813   }
2814 
on_result(BufferSlice packet)2815   void on_result(BufferSlice packet) final {
2816     auto result_ptr = fetch_result<telegram_api::messages_deletePhoneCallHistory>(packet);
2817     if (result_ptr.is_error()) {
2818       return on_error(result_ptr.move_as_error());
2819     }
2820 
2821     auto affected_messages = result_ptr.move_as_ok();
2822     if (!affected_messages->messages_.empty()) {
2823       td_->messages_manager_->process_pts_update(
2824           make_tl_object<telegram_api::updateDeleteMessages>(std::move(affected_messages->messages_), 0, 0));
2825     }
2826     promise_.set_value(AffectedHistory(std::move(affected_messages)));
2827   }
2828 
on_error(Status status)2829   void on_error(Status status) final {
2830     promise_.set_error(std::move(status));
2831   }
2832 };
2833 
2834 class BlockFromRepliesQuery final : public Td::ResultHandler {
2835   Promise<Unit> promise_;
2836 
2837  public:
BlockFromRepliesQuery(Promise<Unit> && promise)2838   explicit BlockFromRepliesQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2839   }
2840 
send(MessageId message_id,bool need_delete_message,bool need_delete_all_messages,bool report_spam)2841   void send(MessageId message_id, bool need_delete_message, bool need_delete_all_messages, bool report_spam) {
2842     int32 flags = 0;
2843     if (need_delete_message) {
2844       flags |= telegram_api::contacts_blockFromReplies::DELETE_MESSAGE_MASK;
2845     }
2846     if (need_delete_all_messages) {
2847       flags |= telegram_api::contacts_blockFromReplies::DELETE_HISTORY_MASK;
2848     }
2849     if (report_spam) {
2850       flags |= telegram_api::contacts_blockFromReplies::REPORT_SPAM_MASK;
2851     }
2852     send_query(G()->net_query_creator().create(telegram_api::contacts_blockFromReplies(
2853         flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, message_id.get_server_message_id().get())));
2854   }
2855 
on_result(BufferSlice packet)2856   void on_result(BufferSlice packet) final {
2857     auto result_ptr = fetch_result<telegram_api::contacts_blockFromReplies>(packet);
2858     if (result_ptr.is_error()) {
2859       return on_error(result_ptr.move_as_error());
2860     }
2861 
2862     auto ptr = result_ptr.move_as_ok();
2863     LOG(INFO) << "Receive result for BlockFromRepliesQuery: " << to_string(ptr);
2864     td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
2865   }
2866 
on_error(Status status)2867   void on_error(Status status) final {
2868     promise_.set_error(std::move(status));
2869   }
2870 };
2871 
2872 class DeleteParticipantHistoryQuery final : public Td::ResultHandler {
2873   Promise<AffectedHistory> promise_;
2874 
2875  public:
DeleteParticipantHistoryQuery(Promise<AffectedHistory> && promise)2876   explicit DeleteParticipantHistoryQuery(Promise<AffectedHistory> &&promise) : promise_(std::move(promise)) {
2877   }
2878 
send(ChannelId channel_id,DialogId sender_dialog_id)2879   void send(ChannelId channel_id, DialogId sender_dialog_id) {
2880     auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
2881     if (input_channel == nullptr) {
2882       return promise_.set_error(Status::Error(400, "Chat is not accessible"));
2883     }
2884     auto input_peer = td_->messages_manager_->get_input_peer(sender_dialog_id, AccessRights::Know);
2885     if (input_peer == nullptr) {
2886       return promise_.set_error(Status::Error(400, "Message sender is not accessible"));
2887     }
2888 
2889     send_query(G()->net_query_creator().create(
2890         telegram_api::channels_deleteParticipantHistory(std::move(input_channel), std::move(input_peer))));
2891   }
2892 
on_result(BufferSlice packet)2893   void on_result(BufferSlice packet) final {
2894     auto result_ptr = fetch_result<telegram_api::channels_deleteParticipantHistory>(packet);
2895     if (result_ptr.is_error()) {
2896       return on_error(result_ptr.move_as_error());
2897     }
2898 
2899     promise_.set_value(AffectedHistory(result_ptr.move_as_ok()));
2900   }
2901 
on_error(Status status)2902   void on_error(Status status) final {
2903     // td_->contacts_manager_->on_get_channel_error(channel_id_, status, "DeleteParticipantHistoryQuery");
2904     promise_.set_error(std::move(status));
2905   }
2906 };
2907 
2908 class ReadMentionsQuery final : public Td::ResultHandler {
2909   Promise<AffectedHistory> promise_;
2910   DialogId dialog_id_;
2911 
2912  public:
ReadMentionsQuery(Promise<AffectedHistory> && promise)2913   explicit ReadMentionsQuery(Promise<AffectedHistory> &&promise) : promise_(std::move(promise)) {
2914   }
2915 
send(DialogId dialog_id)2916   void send(DialogId dialog_id) {
2917     dialog_id_ = dialog_id;
2918 
2919     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id_, AccessRights::Read);
2920     if (input_peer == nullptr) {
2921       return promise_.set_error(Status::Error(400, "Chat is not accessible"));
2922     }
2923 
2924     send_query(G()->net_query_creator().create(telegram_api::messages_readMentions(std::move(input_peer))));
2925   }
2926 
on_result(BufferSlice packet)2927   void on_result(BufferSlice packet) final {
2928     auto result_ptr = fetch_result<telegram_api::messages_readMentions>(packet);
2929     if (result_ptr.is_error()) {
2930       return on_error(result_ptr.move_as_error());
2931     }
2932 
2933     promise_.set_value(AffectedHistory(result_ptr.move_as_ok()));
2934   }
2935 
on_error(Status status)2936   void on_error(Status status) final {
2937     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "ReadMentionsQuery");
2938     promise_.set_error(std::move(status));
2939   }
2940 };
2941 
2942 class SaveDefaultSendAsActor final : public NetActorOnce {
2943   Promise<Unit> promise_;
2944 
2945  public:
SaveDefaultSendAsActor(Promise<Unit> && promise)2946   explicit SaveDefaultSendAsActor(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2947   }
2948 
send(DialogId dialog_id,DialogId send_as_dialog_id,uint64 sequence_dispatcher_id)2949   void send(DialogId dialog_id, DialogId send_as_dialog_id, uint64 sequence_dispatcher_id) {
2950     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
2951     CHECK(input_peer != nullptr);
2952 
2953     auto send_as_input_peer = td_->messages_manager_->get_input_peer(send_as_dialog_id, AccessRights::Read);
2954     CHECK(send_as_input_peer != nullptr);
2955 
2956     auto query = G()->net_query_creator().create(
2957         telegram_api::messages_saveDefaultSendAs(std::move(input_peer), std::move(send_as_input_peer)));
2958     query->debug("send to MessagesManager::MultiSequenceDispatcher");
2959     send_closure(td_->messages_manager_->sequence_dispatcher_, &MultiSequenceDispatcher::send_with_callback,
2960                  std::move(query), actor_shared(this), sequence_dispatcher_id);
2961   }
2962 
on_result(BufferSlice packet)2963   void on_result(BufferSlice packet) final {
2964     auto result_ptr = fetch_result<telegram_api::messages_saveDefaultSendAs>(packet);
2965     if (result_ptr.is_error()) {
2966       return on_error(result_ptr.move_as_error());
2967     }
2968 
2969     auto success = result_ptr.move_as_ok();
2970     LOG(INFO) << "Receive result for SaveDefaultSendAsActor: " << success;
2971 
2972     promise_.set_value(Unit());
2973   }
2974 
on_error(Status status)2975   void on_error(Status status) final {
2976     // td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "SaveDefaultSendAsActor");
2977     promise_.set_error(std::move(status));
2978   }
2979 };
2980 
2981 class SendSecretMessageActor final : public NetActor {
2982   int64 random_id_;
2983 
2984  public:
send(DialogId dialog_id,int64 reply_to_random_id,int32 ttl,const string & text,SecretInputMedia media,vector<tl_object_ptr<secret_api::MessageEntity>> && entities,UserId via_bot_user_id,int64 media_album_id,bool disable_notification,int64 random_id)2985   void send(DialogId dialog_id, int64 reply_to_random_id, int32 ttl, const string &text, SecretInputMedia media,
2986             vector<tl_object_ptr<secret_api::MessageEntity>> &&entities, UserId via_bot_user_id, int64 media_album_id,
2987             bool disable_notification, int64 random_id) {
2988     if (false && !media.empty()) {
2989       td_->messages_manager_->on_send_secret_message_error(random_id, Status::Error(400, "FILE_PART_1_MISSING"),
2990                                                            Auto());
2991       stop();
2992       return;
2993     }
2994 
2995     CHECK(dialog_id.get_type() == DialogType::SecretChat);
2996     random_id_ = random_id;
2997 
2998     int32 flags = 0;
2999     if (reply_to_random_id != 0) {
3000       flags |= secret_api::decryptedMessage::REPLY_TO_RANDOM_ID_MASK;
3001     }
3002     if (via_bot_user_id.is_valid()) {
3003       flags |= secret_api::decryptedMessage::VIA_BOT_NAME_MASK;
3004     }
3005     if (!media.empty()) {
3006       flags |= secret_api::decryptedMessage::MEDIA_MASK;
3007     }
3008     if (!entities.empty()) {
3009       flags |= secret_api::decryptedMessage::ENTITIES_MASK;
3010     }
3011     if (media_album_id != 0) {
3012       CHECK(media_album_id < 0);
3013       flags |= secret_api::decryptedMessage::GROUPED_ID_MASK;
3014     }
3015     if (disable_notification) {
3016       flags |= secret_api::decryptedMessage::SILENT_MASK;
3017     }
3018 
3019     send_closure(
3020         G()->secret_chats_manager(), &SecretChatsManager::send_message, dialog_id.get_secret_chat_id(),
3021         make_tl_object<secret_api::decryptedMessage>(
3022             flags, false /*ignored*/, random_id, ttl, text, std::move(media.decrypted_media_), std::move(entities),
3023             td_->contacts_manager_->get_user_username(via_bot_user_id), reply_to_random_id, -media_album_id),
3024         std::move(media.input_file_), PromiseCreator::event(self_closure(this, &SendSecretMessageActor::done)));
3025   }
3026 
done()3027   void done() {
3028     stop();
3029   }
3030 };
3031 
3032 class SendMessageActor final : public NetActorOnce {
3033   int64 random_id_;
3034   DialogId dialog_id_;
3035 
3036  public:
send(int32 flags,DialogId dialog_id,tl_object_ptr<telegram_api::InputPeer> as_input_peer,MessageId reply_to_message_id,int32 schedule_date,tl_object_ptr<telegram_api::ReplyMarkup> && reply_markup,vector<tl_object_ptr<telegram_api::MessageEntity>> && entities,const string & text,int64 random_id,NetQueryRef * send_query_ref,uint64 sequence_dispatcher_id)3037   void send(int32 flags, DialogId dialog_id, tl_object_ptr<telegram_api::InputPeer> as_input_peer,
3038             MessageId reply_to_message_id, int32 schedule_date, tl_object_ptr<telegram_api::ReplyMarkup> &&reply_markup,
3039             vector<tl_object_ptr<telegram_api::MessageEntity>> &&entities, const string &text, int64 random_id,
3040             NetQueryRef *send_query_ref, uint64 sequence_dispatcher_id) {
3041     random_id_ = random_id;
3042     dialog_id_ = dialog_id;
3043 
3044     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
3045     if (input_peer == nullptr) {
3046       on_error(Status::Error(400, "Have no write access to the chat"));
3047       stop();
3048       return;
3049     }
3050 
3051     if (!entities.empty()) {
3052       flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_ENTITIES;
3053     }
3054     if (as_input_peer != nullptr) {
3055       flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_SEND_AS;
3056     }
3057 
3058     auto query = G()->net_query_creator().create(telegram_api::messages_sendMessage(
3059         flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, std::move(input_peer),
3060         reply_to_message_id.get_server_message_id().get(), text, random_id, std::move(reply_markup),
3061         std::move(entities), schedule_date, std::move(as_input_peer)));
3062     if (G()->shared_config().get_option_boolean("use_quick_ack")) {
3063       query->quick_ack_promise_ = PromiseCreator::lambda(
3064           [random_id](Unit) {
3065             send_closure(G()->messages_manager(), &MessagesManager::on_send_message_get_quick_ack, random_id);
3066           },
3067           PromiseCreator::Ignore());
3068     }
3069     *send_query_ref = query.get_weak();
3070     query->debug("send to MessagesManager::MultiSequenceDispatcher");
3071     send_closure(td_->messages_manager_->sequence_dispatcher_, &MultiSequenceDispatcher::send_with_callback,
3072                  std::move(query), actor_shared(this), sequence_dispatcher_id);
3073   }
3074 
on_result(BufferSlice packet)3075   void on_result(BufferSlice packet) final {
3076     auto result_ptr = fetch_result<telegram_api::messages_sendMessage>(packet);
3077     if (result_ptr.is_error()) {
3078       return on_error(result_ptr.move_as_error());
3079     }
3080 
3081     auto ptr = result_ptr.move_as_ok();
3082     LOG(INFO) << "Receive result for SendMessage for " << random_id_ << ": " << to_string(ptr);
3083 
3084     auto constructor_id = ptr->get_id();
3085     if (constructor_id != telegram_api::updateShortSentMessage::ID) {
3086       td_->messages_manager_->check_send_message_result(random_id_, dialog_id_, ptr.get(), "SendMessage");
3087       return td_->updates_manager_->on_get_updates(std::move(ptr), Promise<Unit>());
3088     }
3089     auto sent_message = move_tl_object_as<telegram_api::updateShortSentMessage>(ptr);
3090     td_->messages_manager_->on_update_sent_text_message(random_id_, std::move(sent_message->media_),
3091                                                         std::move(sent_message->entities_));
3092 
3093     auto message_id = MessageId(ServerMessageId(sent_message->id_));
3094     auto ttl_period = (sent_message->flags_ & telegram_api::updateShortSentMessage::TTL_PERIOD_MASK) != 0
3095                           ? sent_message->ttl_period_
3096                           : 0;
3097     auto update = make_tl_object<updateSentMessage>(random_id_, message_id, sent_message->date_, ttl_period);
3098     if (dialog_id_.get_type() == DialogType::Channel) {
3099       td_->messages_manager_->add_pending_channel_update(dialog_id_, std::move(update), sent_message->pts_,
3100                                                          sent_message->pts_count_, Promise<Unit>(),
3101                                                          "send message actor");
3102       return;
3103     }
3104 
3105     td_->updates_manager_->add_pending_pts_update(std::move(update), sent_message->pts_, sent_message->pts_count_,
3106                                                   Time::now(), Promise<Unit>(), "send message actor");
3107   }
3108 
on_error(Status status)3109   void on_error(Status status) final {
3110     LOG(INFO) << "Receive error for SendMessage: " << status;
3111     if (G()->close_flag() && G()->parameters().use_message_db) {
3112       // do not send error, message will be re-sent
3113       return;
3114     }
3115     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "SendMessageActor");
3116     td_->messages_manager_->on_send_message_fail(random_id_, std::move(status));
3117   }
3118 };
3119 
3120 class StartBotQuery final : public Td::ResultHandler {
3121   int64 random_id_;
3122   DialogId dialog_id_;
3123 
3124  public:
send(tl_object_ptr<telegram_api::InputUser> bot_input_user,DialogId dialog_id,tl_object_ptr<telegram_api::InputPeer> input_peer,const string & parameter,int64 random_id)3125   NetQueryRef send(tl_object_ptr<telegram_api::InputUser> bot_input_user, DialogId dialog_id,
3126                    tl_object_ptr<telegram_api::InputPeer> input_peer, const string &parameter, int64 random_id) {
3127     CHECK(bot_input_user != nullptr);
3128     CHECK(input_peer != nullptr);
3129     random_id_ = random_id;
3130     dialog_id_ = dialog_id;
3131 
3132     auto query = G()->net_query_creator().create(
3133         telegram_api::messages_startBot(std::move(bot_input_user), std::move(input_peer), random_id, parameter));
3134     if (G()->shared_config().get_option_boolean("use_quick_ack")) {
3135       query->quick_ack_promise_ = PromiseCreator::lambda(
3136           [random_id](Unit) {
3137             send_closure(G()->messages_manager(), &MessagesManager::on_send_message_get_quick_ack, random_id);
3138           },
3139           PromiseCreator::Ignore());
3140     }
3141     auto send_query_ref = query.get_weak();
3142     send_query(std::move(query));
3143     return send_query_ref;
3144   }
3145 
on_result(BufferSlice packet)3146   void on_result(BufferSlice packet) final {
3147     auto result_ptr = fetch_result<telegram_api::messages_startBot>(packet);
3148     if (result_ptr.is_error()) {
3149       return on_error(result_ptr.move_as_error());
3150     }
3151 
3152     auto ptr = result_ptr.move_as_ok();
3153     LOG(INFO) << "Receive result for StartBotQuery for " << random_id_ << ": " << to_string(ptr);
3154     // Result may contain messageActionChatAddUser
3155     // td_->messages_manager_->check_send_message_result(random_id_, dialog_id_, ptr.get(), "StartBot");
3156     td_->updates_manager_->on_get_updates(std::move(ptr), Promise<Unit>());
3157   }
3158 
on_error(Status status)3159   void on_error(Status status) final {
3160     LOG(INFO) << "Receive error for StartBotQuery: " << status;
3161     if (G()->close_flag() && G()->parameters().use_message_db) {
3162       // do not send error, message should be re-sent
3163       return;
3164     }
3165     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "StartBotQuery");
3166     td_->messages_manager_->on_send_message_fail(random_id_, std::move(status));
3167   }
3168 };
3169 
3170 class SendInlineBotResultQuery final : public Td::ResultHandler {
3171   int64 random_id_;
3172   DialogId dialog_id_;
3173 
3174  public:
send(int32 flags,DialogId dialog_id,tl_object_ptr<telegram_api::InputPeer> as_input_peer,MessageId reply_to_message_id,int32 schedule_date,int64 random_id,int64 query_id,const string & result_id)3175   NetQueryRef send(int32 flags, DialogId dialog_id, tl_object_ptr<telegram_api::InputPeer> as_input_peer,
3176                    MessageId reply_to_message_id, int32 schedule_date, int64 random_id, int64 query_id,
3177                    const string &result_id) {
3178     random_id_ = random_id;
3179     dialog_id_ = dialog_id;
3180 
3181     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
3182     CHECK(input_peer != nullptr);
3183 
3184     if (as_input_peer != nullptr) {
3185       flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_SEND_AS;
3186     }
3187 
3188     auto query = G()->net_query_creator().create(telegram_api::messages_sendInlineBotResult(
3189         flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, std::move(input_peer),
3190         reply_to_message_id.get_server_message_id().get(), random_id, query_id, result_id, schedule_date,
3191         std::move(as_input_peer)));
3192     auto send_query_ref = query.get_weak();
3193     send_query(std::move(query));
3194     return send_query_ref;
3195   }
3196 
on_result(BufferSlice packet)3197   void on_result(BufferSlice packet) final {
3198     auto result_ptr = fetch_result<telegram_api::messages_sendInlineBotResult>(packet);
3199     if (result_ptr.is_error()) {
3200       return on_error(result_ptr.move_as_error());
3201     }
3202 
3203     auto ptr = result_ptr.move_as_ok();
3204     LOG(INFO) << "Receive result for SendInlineBotResultQuery for " << random_id_ << ": " << to_string(ptr);
3205     td_->messages_manager_->check_send_message_result(random_id_, dialog_id_, ptr.get(), "SendInlineBotResult");
3206     td_->updates_manager_->on_get_updates(std::move(ptr), Promise<Unit>());
3207   }
3208 
on_error(Status status)3209   void on_error(Status status) final {
3210     LOG(INFO) << "Receive error for SendInlineBotResultQuery: " << status;
3211     if (G()->close_flag() && G()->parameters().use_message_db) {
3212       // do not send error, message will be re-sent
3213       return;
3214     }
3215     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "SendInlineBotResultQuery");
3216     td_->messages_manager_->on_send_message_fail(random_id_, std::move(status));
3217   }
3218 };
3219 
3220 class SendMultiMediaActor final : public NetActorOnce {
3221   vector<FileId> file_ids_;
3222   vector<string> file_references_;
3223   vector<int64> random_ids_;
3224   DialogId dialog_id_;
3225 
3226  public:
send(int32 flags,DialogId dialog_id,tl_object_ptr<telegram_api::InputPeer> as_input_peer,MessageId reply_to_message_id,int32 schedule_date,vector<FileId> && file_ids,vector<tl_object_ptr<telegram_api::inputSingleMedia>> && input_single_media,uint64 sequence_dispatcher_id)3227   void send(int32 flags, DialogId dialog_id, tl_object_ptr<telegram_api::InputPeer> as_input_peer,
3228             MessageId reply_to_message_id, int32 schedule_date, vector<FileId> &&file_ids,
3229             vector<tl_object_ptr<telegram_api::inputSingleMedia>> &&input_single_media, uint64 sequence_dispatcher_id) {
3230     for (auto &single_media : input_single_media) {
3231       random_ids_.push_back(single_media->random_id_);
3232       CHECK(FileManager::extract_was_uploaded(single_media->media_) == false);
3233       file_references_.push_back(FileManager::extract_file_reference(single_media->media_));
3234     }
3235     dialog_id_ = dialog_id;
3236     file_ids_ = std::move(file_ids);
3237     CHECK(file_ids_.size() == random_ids_.size());
3238 
3239     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
3240     if (input_peer == nullptr) {
3241       on_error(Status::Error(400, "Have no write access to the chat"));
3242       stop();
3243       return;
3244     }
3245 
3246     if (as_input_peer != nullptr) {
3247       flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_SEND_AS;
3248     }
3249 
3250     auto query = G()->net_query_creator().create(
3251         telegram_api::messages_sendMultiMedia(flags, false /*ignored*/, false /*ignored*/, false /*ignored*/,
3252                                               std::move(input_peer), reply_to_message_id.get_server_message_id().get(),
3253                                               std::move(input_single_media), schedule_date, std::move(as_input_peer)));
3254     // no quick ack, because file reference errors are very likely to happen
3255     query->debug("send to MessagesManager::MultiSequenceDispatcher");
3256     send_closure(td_->messages_manager_->sequence_dispatcher_, &MultiSequenceDispatcher::send_with_callback,
3257                  std::move(query), actor_shared(this), sequence_dispatcher_id);
3258   }
3259 
on_result(BufferSlice packet)3260   void on_result(BufferSlice packet) final {
3261     auto result_ptr = fetch_result<telegram_api::messages_sendMultiMedia>(packet);
3262     if (result_ptr.is_error()) {
3263       return on_error(result_ptr.move_as_error());
3264     }
3265 
3266     auto ptr = result_ptr.move_as_ok();
3267     LOG(INFO) << "Receive result for SendMultiMedia for " << format::as_array(random_ids_) << ": " << to_string(ptr);
3268 
3269     auto sent_random_ids = UpdatesManager::get_sent_messages_random_ids(ptr.get());
3270     bool is_result_wrong = false;
3271     auto sent_random_ids_size = sent_random_ids.size();
3272     for (auto &random_id : random_ids_) {
3273       auto it = sent_random_ids.find(random_id);
3274       if (it == sent_random_ids.end()) {
3275         if (random_ids_.size() == 1) {
3276           is_result_wrong = true;
3277         }
3278         td_->messages_manager_->on_send_message_fail(random_id, Status::Error(400, "Message was not sent"));
3279       } else {
3280         sent_random_ids.erase(it);
3281       }
3282     }
3283     if (!sent_random_ids.empty()) {
3284       is_result_wrong = true;
3285     }
3286     if (!is_result_wrong) {
3287       auto sent_messages = UpdatesManager::get_new_messages(ptr.get());
3288       if (sent_random_ids_size != sent_messages.size()) {
3289         is_result_wrong = true;
3290       }
3291       for (auto &sent_message : sent_messages) {
3292         if (MessagesManager::get_message_dialog_id(*sent_message) != dialog_id_) {
3293           is_result_wrong = true;
3294         }
3295       }
3296     }
3297     if (is_result_wrong) {
3298       LOG(ERROR) << "Receive wrong result for SendMultiMedia with random_ids " << format::as_array(random_ids_)
3299                  << " to " << dialog_id_ << ": " << oneline(to_string(ptr));
3300       td_->updates_manager_->schedule_get_difference("Wrong sendMultiMedia result");
3301     }
3302 
3303     td_->updates_manager_->on_get_updates(std::move(ptr), Promise<Unit>());
3304   }
3305 
on_error(Status status)3306   void on_error(Status status) final {
3307     LOG(INFO) << "Receive error for SendMultiMedia: " << status;
3308     if (G()->close_flag() && G()->parameters().use_message_db) {
3309       // do not send error, message will be re-sent
3310       return;
3311     }
3312     if (!td_->auth_manager_->is_bot() && FileReferenceManager::is_file_reference_error(status)) {
3313       auto pos = FileReferenceManager::get_file_reference_error_pos(status);
3314       if (1 <= pos && pos <= file_ids_.size() && file_ids_[pos - 1].is_valid()) {
3315         VLOG(file_references) << "Receive " << status << " for " << file_ids_[pos - 1];
3316         td_->file_manager_->delete_file_reference(file_ids_[pos - 1], file_references_[pos - 1]);
3317         td_->messages_manager_->on_send_media_group_file_reference_error(dialog_id_, std::move(random_ids_));
3318         return;
3319       } else {
3320         LOG(ERROR) << "Receive file reference error " << status << ", but file_ids = " << file_ids_
3321                    << ", message_count = " << file_ids_.size();
3322       }
3323     }
3324     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "SendMultiMediaActor");
3325     for (auto &random_id : random_ids_) {
3326       td_->messages_manager_->on_send_message_fail(random_id, status.clone());
3327     }
3328   }
3329 };
3330 
3331 class SendMediaActor final : public NetActorOnce {
3332   int64 random_id_ = 0;
3333   FileId file_id_;
3334   FileId thumbnail_file_id_;
3335   DialogId dialog_id_;
3336   string file_reference_;
3337   bool was_uploaded_ = false;
3338   bool was_thumbnail_uploaded_ = false;
3339 
3340  public:
send(FileId file_id,FileId thumbnail_file_id,int32 flags,DialogId dialog_id,tl_object_ptr<telegram_api::InputPeer> as_input_peer,MessageId reply_to_message_id,int32 schedule_date,tl_object_ptr<telegram_api::ReplyMarkup> && reply_markup,vector<tl_object_ptr<telegram_api::MessageEntity>> && entities,const string & text,tl_object_ptr<telegram_api::InputMedia> && input_media,int64 random_id,NetQueryRef * send_query_ref,uint64 sequence_dispatcher_id)3341   void send(FileId file_id, FileId thumbnail_file_id, int32 flags, DialogId dialog_id,
3342             tl_object_ptr<telegram_api::InputPeer> as_input_peer, MessageId reply_to_message_id, int32 schedule_date,
3343             tl_object_ptr<telegram_api::ReplyMarkup> &&reply_markup,
3344             vector<tl_object_ptr<telegram_api::MessageEntity>> &&entities, const string &text,
3345             tl_object_ptr<telegram_api::InputMedia> &&input_media, int64 random_id, NetQueryRef *send_query_ref,
3346             uint64 sequence_dispatcher_id) {
3347     random_id_ = random_id;
3348     file_id_ = file_id;
3349     thumbnail_file_id_ = thumbnail_file_id;
3350     dialog_id_ = dialog_id;
3351     file_reference_ = FileManager::extract_file_reference(input_media);
3352     was_uploaded_ = FileManager::extract_was_uploaded(input_media);
3353     was_thumbnail_uploaded_ = FileManager::extract_was_thumbnail_uploaded(input_media);
3354 
3355     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
3356     if (input_peer == nullptr) {
3357       on_error(Status::Error(400, "Have no write access to the chat"));
3358       stop();
3359       return;
3360     }
3361 
3362     if (!entities.empty()) {
3363       flags |= telegram_api::messages_sendMedia::ENTITIES_MASK;
3364     }
3365     if (as_input_peer != nullptr) {
3366       flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_SEND_AS;
3367     }
3368 
3369     auto query = G()->net_query_creator().create(telegram_api::messages_sendMedia(
3370         flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, std::move(input_peer),
3371         reply_to_message_id.get_server_message_id().get(), std::move(input_media), text, random_id,
3372         std::move(reply_markup), std::move(entities), schedule_date, std::move(as_input_peer)));
3373     if (G()->shared_config().get_option_boolean("use_quick_ack") && was_uploaded_) {
3374       query->quick_ack_promise_ = PromiseCreator::lambda(
3375           [random_id](Unit) {
3376             send_closure(G()->messages_manager(), &MessagesManager::on_send_message_get_quick_ack, random_id);
3377           },
3378           PromiseCreator::Ignore());
3379     }
3380     *send_query_ref = query.get_weak();
3381     query->debug("send to MessagesManager::MultiSequenceDispatcher");
3382     send_closure(td_->messages_manager_->sequence_dispatcher_, &MultiSequenceDispatcher::send_with_callback,
3383                  std::move(query), actor_shared(this), sequence_dispatcher_id);
3384   }
3385 
on_result(BufferSlice packet)3386   void on_result(BufferSlice packet) final {
3387     auto result_ptr = fetch_result<telegram_api::messages_sendMedia>(packet);
3388     if (result_ptr.is_error()) {
3389       return on_error(result_ptr.move_as_error());
3390     }
3391 
3392     if (was_thumbnail_uploaded_) {
3393       CHECK(thumbnail_file_id_.is_valid());
3394       // always delete partial remote location for the thumbnail, because it can't be reused anyway
3395       // TODO delete it only in the case it can't be merged with file thumbnail
3396       td_->file_manager_->delete_partial_remote_location(thumbnail_file_id_);
3397     }
3398 
3399     auto ptr = result_ptr.move_as_ok();
3400     LOG(INFO) << "Receive result for SendMedia for " << random_id_ << ": " << to_string(ptr);
3401     td_->messages_manager_->check_send_message_result(random_id_, dialog_id_, ptr.get(), "SendMedia");
3402     td_->updates_manager_->on_get_updates(std::move(ptr), Promise<Unit>());
3403   }
3404 
on_error(Status status)3405   void on_error(Status status) final {
3406     LOG(INFO) << "Receive error for SendMedia: " << status;
3407     if (G()->close_flag() && G()->parameters().use_message_db) {
3408       // do not send error, message will be re-sent
3409       return;
3410     }
3411     if (was_uploaded_) {
3412       if (was_thumbnail_uploaded_) {
3413         CHECK(thumbnail_file_id_.is_valid());
3414         // always delete partial remote location for the thumbnail, because it can't be reused anyway
3415         td_->file_manager_->delete_partial_remote_location(thumbnail_file_id_);
3416       }
3417 
3418       CHECK(file_id_.is_valid());
3419       if (begins_with(status.message(), "FILE_PART_") && ends_with(status.message(), "_MISSING")) {
3420         td_->messages_manager_->on_send_message_file_part_missing(random_id_,
3421                                                                   to_integer<int32>(status.message().substr(10)));
3422         return;
3423       } else {
3424         if (status.code() != 429 && status.code() < 500 && !G()->close_flag()) {
3425           td_->file_manager_->delete_partial_remote_location(file_id_);
3426         }
3427       }
3428     } else if (!td_->auth_manager_->is_bot() && FileReferenceManager::is_file_reference_error(status)) {
3429       if (file_id_.is_valid() && !was_uploaded_) {
3430         VLOG(file_references) << "Receive " << status << " for " << file_id_;
3431         td_->file_manager_->delete_file_reference(file_id_, file_reference_);
3432         td_->messages_manager_->on_send_message_file_reference_error(random_id_);
3433         return;
3434       } else {
3435         LOG(ERROR) << "Receive file reference error, but file_id = " << file_id_
3436                    << ", was_uploaded = " << was_uploaded_;
3437       }
3438     }
3439 
3440     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "SendMediaActor");
3441     td_->messages_manager_->on_send_message_fail(random_id_, std::move(status));
3442   }
3443 };
3444 
3445 class UploadMediaQuery final : public Td::ResultHandler {
3446   DialogId dialog_id_;
3447   MessageId message_id_;
3448   FileId file_id_;
3449   FileId thumbnail_file_id_;
3450   string file_reference_;
3451   bool was_uploaded_ = false;
3452   bool was_thumbnail_uploaded_ = false;
3453 
3454  public:
send(DialogId dialog_id,MessageId message_id,FileId file_id,FileId thumbnail_file_id,tl_object_ptr<telegram_api::InputMedia> && input_media)3455   void send(DialogId dialog_id, MessageId message_id, FileId file_id, FileId thumbnail_file_id,
3456             tl_object_ptr<telegram_api::InputMedia> &&input_media) {
3457     CHECK(input_media != nullptr);
3458     dialog_id_ = dialog_id;
3459     message_id_ = message_id;
3460     file_id_ = file_id;
3461     thumbnail_file_id_ = thumbnail_file_id;
3462     file_reference_ = FileManager::extract_file_reference(input_media);
3463     was_uploaded_ = FileManager::extract_was_uploaded(input_media);
3464     was_thumbnail_uploaded_ = FileManager::extract_was_thumbnail_uploaded(input_media);
3465 
3466     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
3467     if (input_peer == nullptr) {
3468       return on_error(Status::Error(400, "Have no write access to the chat"));
3469     }
3470 
3471     send_query(G()->net_query_creator().create(
3472         telegram_api::messages_uploadMedia(std::move(input_peer), std::move(input_media))));
3473   }
3474 
on_result(BufferSlice packet)3475   void on_result(BufferSlice packet) final {
3476     auto result_ptr = fetch_result<telegram_api::messages_uploadMedia>(packet);
3477     if (result_ptr.is_error()) {
3478       return on_error(result_ptr.move_as_error());
3479     }
3480 
3481     if (was_thumbnail_uploaded_) {
3482       CHECK(thumbnail_file_id_.is_valid());
3483       // always delete partial remote location for the thumbnail, because it can't be reused anyway
3484       td_->file_manager_->delete_partial_remote_location(thumbnail_file_id_);
3485     }
3486 
3487     auto ptr = result_ptr.move_as_ok();
3488     LOG(INFO) << "Receive result for UploadMediaQuery for " << message_id_ << " in " << dialog_id_ << ": "
3489               << to_string(ptr);
3490     td_->messages_manager_->on_upload_message_media_success(dialog_id_, message_id_, std::move(ptr));
3491   }
3492 
on_error(Status status)3493   void on_error(Status status) final {
3494     LOG(INFO) << "Receive error for UploadMediaQuery for " << message_id_ << " in " << dialog_id_ << ": " << status;
3495     if (G()->close_flag() && G()->parameters().use_message_db) {
3496       // do not send error, message will be re-sent
3497       return;
3498     }
3499     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "UploadMediaQuery");
3500     if (was_uploaded_) {
3501       if (was_thumbnail_uploaded_) {
3502         CHECK(thumbnail_file_id_.is_valid());
3503         // always delete partial remote location for the thumbnail, because it can't be reused anyway
3504         td_->file_manager_->delete_partial_remote_location(thumbnail_file_id_);
3505       }
3506 
3507       CHECK(file_id_.is_valid());
3508       if (begins_with(status.message(), "FILE_PART_") && ends_with(status.message(), "_MISSING")) {
3509         td_->messages_manager_->on_upload_message_media_file_part_missing(
3510             dialog_id_, message_id_, to_integer<int32>(status.message().substr(10)));
3511         return;
3512       } else {
3513         if (status.code() != 429 && status.code() < 500 && !G()->close_flag()) {
3514           td_->file_manager_->delete_partial_remote_location(file_id_);
3515         }
3516       }
3517     } else if (FileReferenceManager::is_file_reference_error(status)) {
3518       LOG(ERROR) << "Receive file reference error for UploadMediaQuery";
3519     }
3520     td_->messages_manager_->on_upload_message_media_fail(dialog_id_, message_id_, std::move(status));
3521   }
3522 };
3523 
3524 class SendScheduledMessageActor final : public NetActorOnce {
3525   Promise<Unit> promise_;
3526   DialogId dialog_id_;
3527 
3528  public:
SendScheduledMessageActor(Promise<Unit> && promise)3529   explicit SendScheduledMessageActor(Promise<Unit> &&promise) : promise_(std::move(promise)) {
3530   }
3531 
send(DialogId dialog_id,MessageId message_id,uint64 sequence_dispatcher_id)3532   void send(DialogId dialog_id, MessageId message_id, uint64 sequence_dispatcher_id) {
3533     dialog_id_ = dialog_id;
3534 
3535     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Edit);
3536     if (input_peer == nullptr) {
3537       on_error(Status::Error(400, "Can't access the chat"));
3538       stop();
3539       return;
3540     }
3541 
3542     int32 server_message_id = message_id.get_scheduled_server_message_id().get();
3543     auto query = G()->net_query_creator().create(
3544         telegram_api::messages_sendScheduledMessages(std::move(input_peer), {server_message_id}));
3545 
3546     query->debug("send to MessagesManager::MultiSequenceDispatcher");
3547     send_closure(td_->messages_manager_->sequence_dispatcher_, &MultiSequenceDispatcher::send_with_callback,
3548                  std::move(query), actor_shared(this), sequence_dispatcher_id);
3549   }
3550 
on_result(BufferSlice packet)3551   void on_result(BufferSlice packet) final {
3552     auto result_ptr = fetch_result<telegram_api::messages_sendScheduledMessages>(packet);
3553     if (result_ptr.is_error()) {
3554       return on_error(result_ptr.move_as_error());
3555     }
3556 
3557     auto ptr = result_ptr.move_as_ok();
3558     LOG(INFO) << "Receive result for SendScheduledMessageActor: " << to_string(ptr);
3559     td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
3560   }
3561 
on_error(Status status)3562   void on_error(Status status) final {
3563     LOG(INFO) << "Receive error for SendScheduledMessageActor: " << status;
3564     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "SendScheduledMessageActor");
3565     promise_.set_error(std::move(status));
3566   }
3567 };
3568 
3569 class EditMessageActor final : public NetActorOnce {
3570   Promise<int32> promise_;
3571   DialogId dialog_id_;
3572 
3573  public:
EditMessageActor(Promise<Unit> && promise)3574   explicit EditMessageActor(Promise<Unit> &&promise) {
3575     promise_ = PromiseCreator::lambda([promise = std::move(promise)](Result<int32> result) mutable {
3576       if (result.is_error()) {
3577         promise.set_error(result.move_as_error());
3578       } else {
3579         promise.set_value(Unit());
3580       }
3581     });
3582   }
EditMessageActor(Promise<int32> && promise)3583   explicit EditMessageActor(Promise<int32> &&promise) : promise_(std::move(promise)) {
3584   }
3585 
send(int32 flags,DialogId dialog_id,MessageId message_id,const string & text,vector<tl_object_ptr<telegram_api::MessageEntity>> && entities,tl_object_ptr<telegram_api::InputMedia> && input_media,tl_object_ptr<telegram_api::ReplyMarkup> && reply_markup,int32 schedule_date,uint64 sequence_dispatcher_id)3586   void send(int32 flags, DialogId dialog_id, MessageId message_id, const string &text,
3587             vector<tl_object_ptr<telegram_api::MessageEntity>> &&entities,
3588             tl_object_ptr<telegram_api::InputMedia> &&input_media,
3589             tl_object_ptr<telegram_api::ReplyMarkup> &&reply_markup, int32 schedule_date,
3590             uint64 sequence_dispatcher_id) {
3591     dialog_id_ = dialog_id;
3592 
3593     if (input_media != nullptr && false) {
3594       on_error(Status::Error(400, "FILE_PART_1_MISSING"));
3595       stop();
3596       return;
3597     }
3598 
3599     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Edit);
3600     if (input_peer == nullptr) {
3601       on_error(Status::Error(400, "Can't access the chat"));
3602       stop();
3603       return;
3604     }
3605 
3606     if (reply_markup != nullptr) {
3607       flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_REPLY_MARKUP;
3608     }
3609     if (!entities.empty()) {
3610       flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_ENTITIES;
3611     }
3612     if (!text.empty()) {
3613       flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_MESSAGE;
3614     }
3615     if (input_media != nullptr) {
3616       flags |= telegram_api::messages_editMessage::MEDIA_MASK;
3617     }
3618     if (schedule_date != 0) {
3619       flags |= telegram_api::messages_editMessage::SCHEDULE_DATE_MASK;
3620     }
3621 
3622     int32 server_message_id = schedule_date != 0 ? message_id.get_scheduled_server_message_id().get()
3623                                                  : message_id.get_server_message_id().get();
3624     auto query = G()->net_query_creator().create(telegram_api::messages_editMessage(
3625         flags, false /*ignored*/, std::move(input_peer), server_message_id, text, std::move(input_media),
3626         std::move(reply_markup), std::move(entities), schedule_date));
3627 
3628     query->debug("send to MessagesManager::MultiSequenceDispatcher");
3629     send_closure(td_->messages_manager_->sequence_dispatcher_, &MultiSequenceDispatcher::send_with_callback,
3630                  std::move(query), actor_shared(this), sequence_dispatcher_id);
3631   }
3632 
on_result(BufferSlice packet)3633   void on_result(BufferSlice packet) final {
3634     auto result_ptr = fetch_result<telegram_api::messages_editMessage>(packet);
3635     if (result_ptr.is_error()) {
3636       return on_error(result_ptr.move_as_error());
3637     }
3638 
3639     auto ptr = result_ptr.move_as_ok();
3640     LOG(INFO) << "Receive result for EditMessageActor: " << to_string(ptr);
3641     auto pts = td_->updates_manager_->get_update_edit_message_pts(ptr.get());
3642     auto promise = PromiseCreator::lambda(
3643         [promise = std::move(promise_), pts](Result<Unit> result) mutable { promise.set_value(std::move(pts)); });
3644     td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise));
3645   }
3646 
on_error(Status status)3647   void on_error(Status status) final {
3648     LOG(INFO) << "Receive error for EditMessage: " << status;
3649     if (!td_->auth_manager_->is_bot() && status.message() == "MESSAGE_NOT_MODIFIED") {
3650       return promise_.set_value(0);
3651     }
3652     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "EditMessageActor");
3653     promise_.set_error(std::move(status));
3654   }
3655 };
3656 
3657 class EditInlineMessageQuery final : public Td::ResultHandler {
3658   Promise<Unit> promise_;
3659 
3660  public:
EditInlineMessageQuery(Promise<Unit> && promise)3661   explicit EditInlineMessageQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
3662   }
3663 
send(int32 flags,tl_object_ptr<telegram_api::InputBotInlineMessageID> input_bot_inline_message_id,const string & text,vector<tl_object_ptr<telegram_api::MessageEntity>> && entities,tl_object_ptr<telegram_api::InputMedia> && input_media,tl_object_ptr<telegram_api::ReplyMarkup> && reply_markup)3664   void send(int32 flags, tl_object_ptr<telegram_api::InputBotInlineMessageID> input_bot_inline_message_id,
3665             const string &text, vector<tl_object_ptr<telegram_api::MessageEntity>> &&entities,
3666             tl_object_ptr<telegram_api::InputMedia> &&input_media,
3667             tl_object_ptr<telegram_api::ReplyMarkup> &&reply_markup) {
3668     CHECK(input_bot_inline_message_id != nullptr);
3669 
3670     // file in an inline message can't be uploaded to another datacenter,
3671     // so only previously uploaded files or URLs can be used in the InputMedia
3672     CHECK(!FileManager::extract_was_uploaded(input_media));
3673 
3674     if (reply_markup != nullptr) {
3675       flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_REPLY_MARKUP;
3676     }
3677     if (!entities.empty()) {
3678       flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_ENTITIES;
3679     }
3680     if (!text.empty()) {
3681       flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_MESSAGE;
3682     }
3683     if (input_media != nullptr) {
3684       flags |= telegram_api::messages_editInlineBotMessage::MEDIA_MASK;
3685     }
3686 
3687     auto dc_id = DcId::internal(InlineQueriesManager::get_inline_message_dc_id(input_bot_inline_message_id));
3688     send_query(G()->net_query_creator().create(
3689         telegram_api::messages_editInlineBotMessage(flags, false /*ignored*/, std::move(input_bot_inline_message_id),
3690                                                     text, std::move(input_media), std::move(reply_markup),
3691                                                     std::move(entities)),
3692         dc_id));
3693   }
3694 
on_result(BufferSlice packet)3695   void on_result(BufferSlice packet) final {
3696     auto result_ptr = fetch_result<telegram_api::messages_editInlineBotMessage>(packet);
3697     if (result_ptr.is_error()) {
3698       return on_error(result_ptr.move_as_error());
3699     }
3700 
3701     LOG_IF(ERROR, !result_ptr.ok()) << "Receive false in result of editInlineMessage";
3702 
3703     promise_.set_value(Unit());
3704   }
3705 
on_error(Status status)3706   void on_error(Status status) final {
3707     LOG(INFO) << "Receive error for EditInlineMessageQuery: " << status;
3708     promise_.set_error(std::move(status));
3709   }
3710 };
3711 
3712 class ForwardMessagesActor final : public NetActorOnce {
3713   Promise<Unit> promise_;
3714   vector<int64> random_ids_;
3715   DialogId from_dialog_id_;
3716   DialogId to_dialog_id_;
3717 
3718  public:
ForwardMessagesActor(Promise<Unit> && promise)3719   explicit ForwardMessagesActor(Promise<Unit> &&promise) : promise_(std::move(promise)) {
3720   }
3721 
send(int32 flags,DialogId to_dialog_id,DialogId from_dialog_id,tl_object_ptr<telegram_api::InputPeer> as_input_peer,const vector<MessageId> & message_ids,vector<int64> && random_ids,int32 schedule_date,uint64 sequence_dispatcher_id)3722   void send(int32 flags, DialogId to_dialog_id, DialogId from_dialog_id,
3723             tl_object_ptr<telegram_api::InputPeer> as_input_peer, const vector<MessageId> &message_ids,
3724             vector<int64> &&random_ids, int32 schedule_date, uint64 sequence_dispatcher_id) {
3725     random_ids_ = random_ids;
3726     from_dialog_id_ = from_dialog_id;
3727     to_dialog_id_ = to_dialog_id;
3728 
3729     auto to_input_peer = td_->messages_manager_->get_input_peer(to_dialog_id, AccessRights::Write);
3730     if (to_input_peer == nullptr) {
3731       on_error(Status::Error(400, "Have no write access to the chat"));
3732       stop();
3733       return;
3734     }
3735 
3736     auto from_input_peer = td_->messages_manager_->get_input_peer(from_dialog_id, AccessRights::Read);
3737     if (from_input_peer == nullptr) {
3738       on_error(Status::Error(400, "Can't access the chat to forward messages from"));
3739       stop();
3740       return;
3741     }
3742 
3743     if (as_input_peer != nullptr) {
3744       flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_SEND_AS;
3745     }
3746 
3747     auto query = G()->net_query_creator().create(telegram_api::messages_forwardMessages(
3748         flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
3749         std::move(from_input_peer), MessagesManager::get_server_message_ids(message_ids), std::move(random_ids),
3750         std::move(to_input_peer), schedule_date, std::move(as_input_peer)));
3751     if (G()->shared_config().get_option_boolean("use_quick_ack")) {
3752       query->quick_ack_promise_ = PromiseCreator::lambda(
3753           [random_ids = random_ids_](Unit) {
3754             for (auto random_id : random_ids) {
3755               send_closure(G()->messages_manager(), &MessagesManager::on_send_message_get_quick_ack, random_id);
3756             }
3757           },
3758           PromiseCreator::Ignore());
3759     }
3760     send_closure(td_->messages_manager_->sequence_dispatcher_, &MultiSequenceDispatcher::send_with_callback,
3761                  std::move(query), actor_shared(this), sequence_dispatcher_id);
3762   }
3763 
on_result(BufferSlice packet)3764   void on_result(BufferSlice packet) final {
3765     auto result_ptr = fetch_result<telegram_api::messages_forwardMessages>(packet);
3766     if (result_ptr.is_error()) {
3767       return on_error(result_ptr.move_as_error());
3768     }
3769 
3770     auto ptr = result_ptr.move_as_ok();
3771     LOG(INFO) << "Receive result for ForwardMessages for " << format::as_array(random_ids_) << ": " << to_string(ptr);
3772     auto sent_random_ids = UpdatesManager::get_sent_messages_random_ids(ptr.get());
3773     bool is_result_wrong = false;
3774     auto sent_random_ids_size = sent_random_ids.size();
3775     for (auto &random_id : random_ids_) {
3776       auto it = sent_random_ids.find(random_id);
3777       if (it == sent_random_ids.end()) {
3778         if (random_ids_.size() == 1) {
3779           is_result_wrong = true;
3780         }
3781         td_->messages_manager_->on_send_message_fail(random_id, Status::Error(400, "Message was not forwarded"));
3782       } else {
3783         sent_random_ids.erase(it);
3784       }
3785     }
3786     if (!sent_random_ids.empty()) {
3787       is_result_wrong = true;
3788     }
3789     if (!is_result_wrong) {
3790       auto sent_messages = UpdatesManager::get_new_messages(ptr.get());
3791       if (sent_random_ids_size != sent_messages.size()) {
3792         is_result_wrong = true;
3793       }
3794       for (auto &sent_message : sent_messages) {
3795         if (MessagesManager::get_message_dialog_id(*sent_message) != to_dialog_id_) {
3796           is_result_wrong = true;
3797         }
3798       }
3799     }
3800     if (is_result_wrong) {
3801       LOG(ERROR) << "Receive wrong result for forwarding messages with random_ids " << format::as_array(random_ids_)
3802                  << " to " << to_dialog_id_ << ": " << oneline(to_string(ptr));
3803       td_->updates_manager_->schedule_get_difference("Wrong forwardMessages result");
3804     }
3805 
3806     td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
3807   }
3808 
on_error(Status status)3809   void on_error(Status status) final {
3810     LOG(INFO) << "Receive error for forward messages: " << status;
3811     if (G()->close_flag() && G()->parameters().use_message_db) {
3812       // do not send error, messages should be re-sent
3813       return;
3814     }
3815     // no on_get_dialog_error call, because two dialogs are involved
3816     if (status.code() == 400 && status.message() == CSlice("CHAT_FORWARDS_RESTRICTED")) {
3817       td_->contacts_manager_->reload_dialog_info(from_dialog_id_, Promise<Unit>());
3818     }
3819     if (status.code() == 400 && status.message() == CSlice("SEND_AS_PEER_INVALID")) {
3820       td_->messages_manager_->reload_dialog_info_full(to_dialog_id_);
3821     }
3822     for (auto &random_id : random_ids_) {
3823       td_->messages_manager_->on_send_message_fail(random_id, status.clone());
3824     }
3825     promise_.set_error(std::move(status));
3826   }
3827 };
3828 
3829 class SendScreenshotNotificationQuery final : public Td::ResultHandler {
3830   Promise<Unit> promise_;
3831   int64 random_id_;
3832   DialogId dialog_id_;
3833 
3834  public:
SendScreenshotNotificationQuery(Promise<Unit> && promise)3835   explicit SendScreenshotNotificationQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
3836   }
3837 
send(DialogId dialog_id,int64 random_id)3838   void send(DialogId dialog_id, int64 random_id) {
3839     random_id_ = random_id;
3840     dialog_id_ = dialog_id;
3841 
3842     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
3843     CHECK(input_peer != nullptr);
3844 
3845     auto query = G()->net_query_creator().create(
3846         telegram_api::messages_sendScreenshotNotification(std::move(input_peer), 0, random_id));
3847     send_query(std::move(query));
3848   }
3849 
on_result(BufferSlice packet)3850   void on_result(BufferSlice packet) final {
3851     auto result_ptr = fetch_result<telegram_api::messages_sendScreenshotNotification>(packet);
3852     if (result_ptr.is_error()) {
3853       return on_error(result_ptr.move_as_error());
3854     }
3855 
3856     auto ptr = result_ptr.move_as_ok();
3857     LOG(INFO) << "Receive result for SendScreenshotNotificationQuery for " << random_id_ << ": " << to_string(ptr);
3858     td_->messages_manager_->check_send_message_result(random_id_, dialog_id_, ptr.get(),
3859                                                       "SendScreenshotNotificationQuery");
3860     td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
3861   }
3862 
on_error(Status status)3863   void on_error(Status status) final {
3864     LOG(INFO) << "Receive error for SendScreenshotNotificationQuery: " << status;
3865     if (G()->close_flag() && G()->parameters().use_message_db) {
3866       // do not send error, messages should be re-sent
3867       return;
3868     }
3869     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "SendScreenshotNotificationQuery");
3870     td_->messages_manager_->on_send_message_fail(random_id_, status.clone());
3871     promise_.set_error(std::move(status));
3872   }
3873 };
3874 
3875 class SetTypingQuery final : public Td::ResultHandler {
3876   Promise<Unit> promise_;
3877   DialogId dialog_id_;
3878   int32 generation_ = 0;
3879 
3880  public:
SetTypingQuery(Promise<Unit> && promise)3881   explicit SetTypingQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
3882   }
3883 
send(DialogId dialog_id,tl_object_ptr<telegram_api::InputPeer> && input_peer,MessageId message_id,tl_object_ptr<telegram_api::SendMessageAction> && action)3884   NetQueryRef send(DialogId dialog_id, tl_object_ptr<telegram_api::InputPeer> &&input_peer, MessageId message_id,
3885                    tl_object_ptr<telegram_api::SendMessageAction> &&action) {
3886     dialog_id_ = dialog_id;
3887     CHECK(input_peer != nullptr);
3888 
3889     int32 flags = 0;
3890     if (message_id.is_valid()) {
3891       flags |= telegram_api::messages_setTyping::TOP_MSG_ID_MASK;
3892     }
3893     auto net_query = G()->net_query_creator().create(telegram_api::messages_setTyping(
3894         flags, std::move(input_peer), message_id.get_server_message_id().get(), std::move(action)));
3895     auto result = net_query.get_weak();
3896     generation_ = result.generation();
3897     send_query(std::move(net_query));
3898     return result;
3899   }
3900 
on_result(BufferSlice packet)3901   void on_result(BufferSlice packet) final {
3902     auto result_ptr = fetch_result<telegram_api::messages_setTyping>(packet);
3903     if (result_ptr.is_error()) {
3904       return on_error(result_ptr.move_as_error());
3905     }
3906 
3907     // ignore result
3908     promise_.set_value(Unit());
3909 
3910     send_closure_later(G()->messages_manager(), &MessagesManager::after_set_typing_query, dialog_id_, generation_);
3911   }
3912 
on_error(Status status)3913   void on_error(Status status) final {
3914     if (status.code() == NetQuery::Canceled) {
3915       return promise_.set_value(Unit());
3916     }
3917 
3918     if (!td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "SetTypingQuery")) {
3919       LOG(INFO) << "Receive error for set typing: " << status;
3920     }
3921     promise_.set_error(std::move(status));
3922 
3923     send_closure_later(G()->messages_manager(), &MessagesManager::after_set_typing_query, dialog_id_, generation_);
3924   }
3925 };
3926 
3927 class DeleteMessagesQuery final : public Td::ResultHandler {
3928   Promise<Unit> promise_;
3929   DialogId dialog_id_;
3930 
3931  public:
DeleteMessagesQuery(Promise<Unit> && promise)3932   explicit DeleteMessagesQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
3933   }
3934 
send(DialogId dialog_id,vector<int32> && server_message_ids,bool revoke)3935   void send(DialogId dialog_id, vector<int32> &&server_message_ids, bool revoke) {
3936     dialog_id_ = dialog_id;
3937     int32 flags = 0;
3938     if (revoke) {
3939       flags |= telegram_api::messages_deleteMessages::REVOKE_MASK;
3940     }
3941 
3942     send_query(G()->net_query_creator().create(
3943         telegram_api::messages_deleteMessages(flags, false /*ignored*/, std::move(server_message_ids))));
3944   }
3945 
on_result(BufferSlice packet)3946   void on_result(BufferSlice packet) final {
3947     auto result_ptr = fetch_result<telegram_api::messages_deleteMessages>(packet);
3948     if (result_ptr.is_error()) {
3949       return on_error(result_ptr.move_as_error());
3950     }
3951 
3952     auto affected_messages = result_ptr.move_as_ok();
3953     if (affected_messages->pts_count_ > 0) {
3954       td_->updates_manager_->add_pending_pts_update(make_tl_object<dummyUpdate>(), affected_messages->pts_,
3955                                                     affected_messages->pts_count_, Time::now(), std::move(promise_),
3956                                                     "delete messages query");
3957     } else {
3958       promise_.set_value(Unit());
3959     }
3960   }
3961 
on_error(Status status)3962   void on_error(Status status) final {
3963     if (!G()->is_expected_error(status)) {
3964       // MESSAGE_DELETE_FORBIDDEN can be returned in group chats when administrator rights was removed
3965       // MESSAGE_DELETE_FORBIDDEN can be returned in private chats for bots when revoke time limit exceeded
3966       if (status.message() != "MESSAGE_DELETE_FORBIDDEN" ||
3967           (dialog_id_.get_type() == DialogType::User && !td_->auth_manager_->is_bot())) {
3968         LOG(ERROR) << "Receive error for delete messages: " << status;
3969       }
3970     }
3971     promise_.set_error(std::move(status));
3972   }
3973 };
3974 
3975 class DeleteChannelMessagesQuery final : public Td::ResultHandler {
3976   Promise<Unit> promise_;
3977   ChannelId channel_id_;
3978 
3979  public:
DeleteChannelMessagesQuery(Promise<Unit> && promise)3980   explicit DeleteChannelMessagesQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
3981   }
3982 
send(ChannelId channel_id,vector<int32> && server_message_ids)3983   void send(ChannelId channel_id, vector<int32> &&server_message_ids) {
3984     channel_id_ = channel_id;
3985     auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
3986     CHECK(input_channel != nullptr);
3987     send_query(G()->net_query_creator().create(
3988         telegram_api::channels_deleteMessages(std::move(input_channel), std::move(server_message_ids))));
3989   }
3990 
on_result(BufferSlice packet)3991   void on_result(BufferSlice packet) final {
3992     auto result_ptr = fetch_result<telegram_api::channels_deleteMessages>(packet);
3993     if (result_ptr.is_error()) {
3994       return on_error(result_ptr.move_as_error());
3995     }
3996 
3997     auto affected_messages = result_ptr.move_as_ok();
3998     if (affected_messages->pts_count_ > 0) {
3999       td_->messages_manager_->add_pending_channel_update(DialogId(channel_id_), make_tl_object<dummyUpdate>(),
4000                                                          affected_messages->pts_, affected_messages->pts_count_,
4001                                                          std::move(promise_), "DeleteChannelMessagesQuery");
4002     } else {
4003       promise_.set_value(Unit());
4004     }
4005   }
4006 
on_error(Status status)4007   void on_error(Status status) final {
4008     if (!td_->contacts_manager_->on_get_channel_error(channel_id_, status, "DeleteChannelMessagesQuery") &&
4009         status.message() != "MESSAGE_DELETE_FORBIDDEN") {
4010       LOG(ERROR) << "Receive error for delete channel messages: " << status;
4011     }
4012     promise_.set_error(std::move(status));
4013   }
4014 };
4015 
4016 class DeleteScheduledMessagesQuery final : public Td::ResultHandler {
4017   Promise<Unit> promise_;
4018   DialogId dialog_id_;
4019 
4020  public:
DeleteScheduledMessagesQuery(Promise<Unit> && promise)4021   explicit DeleteScheduledMessagesQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
4022   }
4023 
send(DialogId dialog_id,vector<MessageId> && message_ids)4024   void send(DialogId dialog_id, vector<MessageId> &&message_ids) {
4025     dialog_id_ = dialog_id;
4026 
4027     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
4028     if (input_peer == nullptr) {
4029       return on_error(Status::Error(400, "Can't access the chat"));
4030     }
4031     send_query(G()->net_query_creator().create(telegram_api::messages_deleteScheduledMessages(
4032         std::move(input_peer), MessagesManager::get_scheduled_server_message_ids(message_ids))));
4033   }
4034 
on_result(BufferSlice packet)4035   void on_result(BufferSlice packet) final {
4036     auto result_ptr = fetch_result<telegram_api::messages_deleteScheduledMessages>(packet);
4037     if (result_ptr.is_error()) {
4038       return on_error(result_ptr.move_as_error());
4039     }
4040 
4041     auto ptr = result_ptr.move_as_ok();
4042     LOG(INFO) << "Receive result for DeleteScheduledMessagesQuery: " << to_string(ptr);
4043     td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
4044   }
4045 
on_error(Status status)4046   void on_error(Status status) final {
4047     if (!td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "DeleteScheduledMessagesQuery")) {
4048       LOG(ERROR) << "Receive error for delete scheduled messages: " << status;
4049     }
4050     promise_.set_error(std::move(status));
4051   }
4052 };
4053 
4054 class GetDialogNotifySettingsQuery final : public Td::ResultHandler {
4055   DialogId dialog_id_;
4056 
4057  public:
send(DialogId dialog_id)4058   void send(DialogId dialog_id) {
4059     dialog_id_ = dialog_id;
4060     auto input_notify_peer = td_->messages_manager_->get_input_notify_peer(dialog_id);
4061     CHECK(input_notify_peer != nullptr);
4062     send_query(G()->net_query_creator().create(telegram_api::account_getNotifySettings(std::move(input_notify_peer))));
4063   }
4064 
on_result(BufferSlice packet)4065   void on_result(BufferSlice packet) final {
4066     auto result_ptr = fetch_result<telegram_api::account_getNotifySettings>(packet);
4067     if (result_ptr.is_error()) {
4068       return on_error(result_ptr.move_as_error());
4069     }
4070 
4071     auto ptr = result_ptr.move_as_ok();
4072     td_->messages_manager_->on_update_dialog_notify_settings(dialog_id_, std::move(ptr),
4073                                                              "GetDialogNotifySettingsQuery");
4074     td_->messages_manager_->on_get_dialog_notification_settings_query_finished(dialog_id_, Status::OK());
4075   }
4076 
on_error(Status status)4077   void on_error(Status status) final {
4078     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetDialogNotifySettingsQuery");
4079     td_->messages_manager_->on_get_dialog_notification_settings_query_finished(dialog_id_, std::move(status));
4080   }
4081 };
4082 
4083 class GetNotifySettingsExceptionsQuery final : public Td::ResultHandler {
4084   Promise<Unit> promise_;
4085 
4086  public:
GetNotifySettingsExceptionsQuery(Promise<Unit> && promise)4087   explicit GetNotifySettingsExceptionsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
4088   }
4089 
send(NotificationSettingsScope scope,bool filter_scope,bool compare_sound)4090   void send(NotificationSettingsScope scope, bool filter_scope, bool compare_sound) {
4091     int32 flags = 0;
4092     tl_object_ptr<telegram_api::InputNotifyPeer> input_notify_peer;
4093     if (filter_scope) {
4094       flags |= telegram_api::account_getNotifyExceptions::PEER_MASK;
4095       input_notify_peer = get_input_notify_peer(scope);
4096     }
4097     if (compare_sound) {
4098       flags |= telegram_api::account_getNotifyExceptions::COMPARE_SOUND_MASK;
4099     }
4100     send_query(G()->net_query_creator().create(
4101         telegram_api::account_getNotifyExceptions(flags, false /* ignored */, std::move(input_notify_peer))));
4102   }
4103 
on_result(BufferSlice packet)4104   void on_result(BufferSlice packet) final {
4105     auto result_ptr = fetch_result<telegram_api::account_getNotifyExceptions>(packet);
4106     if (result_ptr.is_error()) {
4107       return on_error(result_ptr.move_as_error());
4108     }
4109 
4110     auto updates_ptr = result_ptr.move_as_ok();
4111     auto dialog_ids = UpdatesManager::get_update_notify_settings_dialog_ids(updates_ptr.get());
4112     vector<tl_object_ptr<telegram_api::User>> users;
4113     vector<tl_object_ptr<telegram_api::Chat>> chats;
4114     switch (updates_ptr->get_id()) {
4115       case telegram_api::updatesCombined::ID: {
4116         auto updates = static_cast<telegram_api::updatesCombined *>(updates_ptr.get());
4117         users = std::move(updates->users_);
4118         chats = std::move(updates->chats_);
4119         reset_to_empty(updates->users_);
4120         reset_to_empty(updates->chats_);
4121         break;
4122       }
4123       case telegram_api::updates::ID: {
4124         auto updates = static_cast<telegram_api::updates *>(updates_ptr.get());
4125         users = std::move(updates->users_);
4126         chats = std::move(updates->chats_);
4127         reset_to_empty(updates->users_);
4128         reset_to_empty(updates->chats_);
4129         break;
4130       }
4131     }
4132     td_->contacts_manager_->on_get_users(std::move(users), "GetNotifySettingsExceptionsQuery");
4133     td_->contacts_manager_->on_get_chats(std::move(chats), "GetNotifySettingsExceptionsQuery");
4134     for (auto &dialog_id : dialog_ids) {
4135       td_->messages_manager_->force_create_dialog(dialog_id, "GetNotifySettingsExceptionsQuery");
4136     }
4137     td_->updates_manager_->on_get_updates(std::move(updates_ptr), std::move(promise_));
4138   }
4139 
on_error(Status status)4140   void on_error(Status status) final {
4141     promise_.set_error(std::move(status));
4142   }
4143 };
4144 
4145 class GetScopeNotifySettingsQuery final : public Td::ResultHandler {
4146   Promise<Unit> promise_;
4147   NotificationSettingsScope scope_;
4148 
4149  public:
GetScopeNotifySettingsQuery(Promise<Unit> && promise)4150   explicit GetScopeNotifySettingsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
4151   }
4152 
send(NotificationSettingsScope scope)4153   void send(NotificationSettingsScope scope) {
4154     scope_ = scope;
4155     auto input_notify_peer = get_input_notify_peer(scope);
4156     CHECK(input_notify_peer != nullptr);
4157     send_query(G()->net_query_creator().create(telegram_api::account_getNotifySettings(std::move(input_notify_peer))));
4158   }
4159 
on_result(BufferSlice packet)4160   void on_result(BufferSlice packet) final {
4161     auto result_ptr = fetch_result<telegram_api::account_getNotifySettings>(packet);
4162     if (result_ptr.is_error()) {
4163       return on_error(result_ptr.move_as_error());
4164     }
4165 
4166     auto ptr = result_ptr.move_as_ok();
4167     td_->messages_manager_->on_update_scope_notify_settings(scope_, std::move(ptr));
4168 
4169     promise_.set_value(Unit());
4170   }
4171 
on_error(Status status)4172   void on_error(Status status) final {
4173     promise_.set_error(std::move(status));
4174   }
4175 };
4176 
4177 class UpdateDialogNotifySettingsQuery final : public Td::ResultHandler {
4178   Promise<Unit> promise_;
4179   DialogId dialog_id_;
4180 
4181  public:
UpdateDialogNotifySettingsQuery(Promise<Unit> && promise)4182   explicit UpdateDialogNotifySettingsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
4183   }
4184 
send(DialogId dialog_id,const DialogNotificationSettings & new_settings)4185   void send(DialogId dialog_id, const DialogNotificationSettings &new_settings) {
4186     dialog_id_ = dialog_id;
4187 
4188     auto input_notify_peer = td_->messages_manager_->get_input_notify_peer(dialog_id);
4189     if (input_notify_peer == nullptr) {
4190       return on_error(Status::Error(500, "Can't update chat notification settings"));
4191     }
4192 
4193     int32 flags = 0;
4194     if (!new_settings.use_default_mute_until) {
4195       flags |= telegram_api::inputPeerNotifySettings::MUTE_UNTIL_MASK;
4196     }
4197     if (!new_settings.use_default_sound) {
4198       flags |= telegram_api::inputPeerNotifySettings::SOUND_MASK;
4199     }
4200     if (!new_settings.use_default_show_preview) {
4201       flags |= telegram_api::inputPeerNotifySettings::SHOW_PREVIEWS_MASK;
4202     }
4203     if (new_settings.silent_send_message) {
4204       flags |= telegram_api::inputPeerNotifySettings::SILENT_MASK;
4205     }
4206     send_query(G()->net_query_creator().create(telegram_api::account_updateNotifySettings(
4207         std::move(input_notify_peer), make_tl_object<telegram_api::inputPeerNotifySettings>(
4208                                           flags, new_settings.show_preview, new_settings.silent_send_message,
4209                                           new_settings.mute_until, new_settings.sound))));
4210   }
4211 
on_result(BufferSlice packet)4212   void on_result(BufferSlice packet) final {
4213     auto result_ptr = fetch_result<telegram_api::account_updateNotifySettings>(packet);
4214     if (result_ptr.is_error()) {
4215       return on_error(result_ptr.move_as_error());
4216     }
4217 
4218     bool result = result_ptr.ok();
4219     if (!result) {
4220       return on_error(Status::Error(400, "Receive false as result"));
4221     }
4222 
4223     promise_.set_value(Unit());
4224   }
4225 
on_error(Status status)4226   void on_error(Status status) final {
4227     if (!td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "UpdateDialogNotifySettingsQuery")) {
4228       LOG(INFO) << "Receive error for set chat notification settings: " << status;
4229     }
4230 
4231     if (!td_->auth_manager_->is_bot() && td_->messages_manager_->get_input_notify_peer(dialog_id_) != nullptr) {
4232       // trying to repair notification settings for this dialog
4233       td_->messages_manager_->send_get_dialog_notification_settings_query(dialog_id_, Promise<>());
4234     }
4235 
4236     promise_.set_error(std::move(status));
4237   }
4238 };
4239 
4240 class UpdateScopeNotifySettingsQuery final : public Td::ResultHandler {
4241   Promise<Unit> promise_;
4242   NotificationSettingsScope scope_;
4243 
4244  public:
UpdateScopeNotifySettingsQuery(Promise<Unit> && promise)4245   explicit UpdateScopeNotifySettingsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
4246   }
4247 
send(NotificationSettingsScope scope,const ScopeNotificationSettings & new_settings)4248   void send(NotificationSettingsScope scope, const ScopeNotificationSettings &new_settings) {
4249     auto input_notify_peer = get_input_notify_peer(scope);
4250     CHECK(input_notify_peer != nullptr);
4251     int32 flags = telegram_api::inputPeerNotifySettings::MUTE_UNTIL_MASK |
4252                   telegram_api::inputPeerNotifySettings::SOUND_MASK |
4253                   telegram_api::inputPeerNotifySettings::SHOW_PREVIEWS_MASK;
4254     send_query(G()->net_query_creator().create(telegram_api::account_updateNotifySettings(
4255         std::move(input_notify_peer),
4256         make_tl_object<telegram_api::inputPeerNotifySettings>(flags, new_settings.show_preview, false,
4257                                                               new_settings.mute_until, new_settings.sound))));
4258     scope_ = scope;
4259   }
4260 
on_result(BufferSlice packet)4261   void on_result(BufferSlice packet) final {
4262     auto result_ptr = fetch_result<telegram_api::account_updateNotifySettings>(packet);
4263     if (result_ptr.is_error()) {
4264       return on_error(result_ptr.move_as_error());
4265     }
4266 
4267     bool result = result_ptr.ok();
4268     if (!result) {
4269       return on_error(Status::Error(400, "Receive false as result"));
4270     }
4271 
4272     promise_.set_value(Unit());
4273   }
4274 
on_error(Status status)4275   void on_error(Status status) final {
4276     LOG(INFO) << "Receive error for set notification settings: " << status;
4277 
4278     if (!td_->auth_manager_->is_bot()) {
4279       // trying to repair notification settings for this scope
4280       td_->messages_manager_->send_get_scope_notification_settings_query(scope_, Promise<>());
4281     }
4282 
4283     promise_.set_error(std::move(status));
4284   }
4285 };
4286 
4287 class ResetNotifySettingsQuery final : public Td::ResultHandler {
4288   Promise<Unit> promise_;
4289 
4290  public:
ResetNotifySettingsQuery(Promise<Unit> && promise)4291   explicit ResetNotifySettingsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
4292   }
4293 
send()4294   void send() {
4295     send_query(G()->net_query_creator().create(telegram_api::account_resetNotifySettings()));
4296   }
4297 
on_result(BufferSlice packet)4298   void on_result(BufferSlice packet) final {
4299     auto result_ptr = fetch_result<telegram_api::account_resetNotifySettings>(packet);
4300     if (result_ptr.is_error()) {
4301       return on_error(result_ptr.move_as_error());
4302     }
4303 
4304     bool result = result_ptr.ok();
4305     if (!result) {
4306       return on_error(Status::Error(400, "Receive false as result"));
4307     }
4308 
4309     promise_.set_value(Unit());
4310   }
4311 
on_error(Status status)4312   void on_error(Status status) final {
4313     if (!G()->is_expected_error(status)) {
4314       LOG(ERROR) << "Receive error for reset notification settings: " << status;
4315     }
4316     promise_.set_error(std::move(status));
4317   }
4318 };
4319 
4320 class GetPeerSettingsQuery final : public Td::ResultHandler {
4321   DialogId dialog_id_;
4322 
4323  public:
send(DialogId dialog_id)4324   void send(DialogId dialog_id) {
4325     dialog_id_ = dialog_id;
4326 
4327     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
4328     CHECK(input_peer != nullptr);
4329 
4330     send_query(G()->net_query_creator().create(telegram_api::messages_getPeerSettings(std::move(input_peer))));
4331   }
4332 
on_result(BufferSlice packet)4333   void on_result(BufferSlice packet) final {
4334     auto result_ptr = fetch_result<telegram_api::messages_getPeerSettings>(packet);
4335     if (result_ptr.is_error()) {
4336       return on_error(result_ptr.move_as_error());
4337     }
4338 
4339     auto ptr = result_ptr.move_as_ok();
4340     td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetPeerSettingsQuery");
4341     td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetPeerSettingsQuery");
4342     td_->messages_manager_->on_get_peer_settings(dialog_id_, std::move(ptr->settings_));
4343   }
4344 
on_error(Status status)4345   void on_error(Status status) final {
4346     LOG(INFO) << "Receive error for get peer settings: " << status;
4347     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetPeerSettingsQuery");
4348   }
4349 };
4350 
4351 class UpdatePeerSettingsQuery final : public Td::ResultHandler {
4352   Promise<Unit> promise_;
4353   DialogId dialog_id_;
4354 
4355  public:
UpdatePeerSettingsQuery(Promise<Unit> && promise)4356   explicit UpdatePeerSettingsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
4357   }
4358 
send(DialogId dialog_id,bool is_spam_dialog)4359   void send(DialogId dialog_id, bool is_spam_dialog) {
4360     dialog_id_ = dialog_id;
4361 
4362     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
4363     if (input_peer == nullptr) {
4364       return promise_.set_value(Unit());
4365     }
4366 
4367     if (is_spam_dialog) {
4368       send_query(G()->net_query_creator().create(telegram_api::messages_reportSpam(std::move(input_peer))));
4369     } else {
4370       send_query(G()->net_query_creator().create(telegram_api::messages_hidePeerSettingsBar(std::move(input_peer))));
4371     }
4372   }
4373 
on_result(BufferSlice packet)4374   void on_result(BufferSlice packet) final {
4375     static_assert(std::is_same<telegram_api::messages_reportSpam::ReturnType,
4376                                telegram_api::messages_hidePeerSettingsBar::ReturnType>::value,
4377                   "");
4378     auto result_ptr = fetch_result<telegram_api::messages_reportSpam>(packet);
4379     if (result_ptr.is_error()) {
4380       return on_error(result_ptr.move_as_error());
4381     }
4382 
4383     td_->messages_manager_->on_get_peer_settings(dialog_id_, make_tl_object<telegram_api::peerSettings>(), true);
4384 
4385     promise_.set_value(Unit());
4386   }
4387 
on_error(Status status)4388   void on_error(Status status) final {
4389     LOG(INFO) << "Receive error for update peer settings: " << status;
4390     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "UpdatePeerSettingsQuery");
4391     td_->messages_manager_->reget_dialog_action_bar(dialog_id_, "UpdatePeerSettingsQuery");
4392     promise_.set_error(std::move(status));
4393   }
4394 };
4395 
4396 class ReportEncryptedSpamQuery final : public Td::ResultHandler {
4397   Promise<Unit> promise_;
4398   DialogId dialog_id_;
4399 
4400  public:
ReportEncryptedSpamQuery(Promise<Unit> && promise)4401   explicit ReportEncryptedSpamQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
4402   }
4403 
send(DialogId dialog_id)4404   void send(DialogId dialog_id) {
4405     dialog_id_ = dialog_id;
4406 
4407     auto input_peer = td_->messages_manager_->get_input_encrypted_chat(dialog_id, AccessRights::Read);
4408     CHECK(input_peer != nullptr);
4409 
4410     send_query(G()->net_query_creator().create(telegram_api::messages_reportEncryptedSpam(std::move(input_peer))));
4411   }
4412 
on_result(BufferSlice packet)4413   void on_result(BufferSlice packet) final {
4414     auto result_ptr = fetch_result<telegram_api::messages_reportEncryptedSpam>(packet);
4415     if (result_ptr.is_error()) {
4416       return on_error(result_ptr.move_as_error());
4417     }
4418 
4419     td_->messages_manager_->on_get_peer_settings(dialog_id_, make_tl_object<telegram_api::peerSettings>(), true);
4420 
4421     promise_.set_value(Unit());
4422   }
4423 
on_error(Status status)4424   void on_error(Status status) final {
4425     LOG(INFO) << "Receive error for report encrypted spam: " << status;
4426     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "ReportEncryptedSpamQuery");
4427     td_->messages_manager_->reget_dialog_action_bar(
4428         DialogId(td_->contacts_manager_->get_secret_chat_user_id(dialog_id_.get_secret_chat_id())),
4429         "ReportEncryptedSpamQuery");
4430     promise_.set_error(std::move(status));
4431   }
4432 };
4433 
4434 class ReportPeerQuery final : public Td::ResultHandler {
4435   Promise<Unit> promise_;
4436   DialogId dialog_id_;
4437 
4438  public:
ReportPeerQuery(Promise<Unit> && promise)4439   explicit ReportPeerQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
4440   }
4441 
send(DialogId dialog_id,const vector<MessageId> & message_ids,ReportReason && report_reason)4442   void send(DialogId dialog_id, const vector<MessageId> &message_ids, ReportReason &&report_reason) {
4443     dialog_id_ = dialog_id;
4444 
4445     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
4446     CHECK(input_peer != nullptr);
4447 
4448     if (message_ids.empty()) {
4449       send_query(G()->net_query_creator().create(telegram_api::account_reportPeer(
4450           std::move(input_peer), report_reason.get_input_report_reason(), report_reason.get_message())));
4451     } else {
4452       send_query(G()->net_query_creator().create(
4453           telegram_api::messages_report(std::move(input_peer), MessagesManager::get_server_message_ids(message_ids),
4454                                         report_reason.get_input_report_reason(), report_reason.get_message())));
4455     }
4456   }
4457 
on_result(BufferSlice packet)4458   void on_result(BufferSlice packet) final {
4459     static_assert(
4460         std::is_same<telegram_api::account_reportPeer::ReturnType, telegram_api::messages_report::ReturnType>::value,
4461         "");
4462     auto result_ptr = fetch_result<telegram_api::account_reportPeer>(packet);
4463     if (result_ptr.is_error()) {
4464       return on_error(result_ptr.move_as_error());
4465     }
4466 
4467     bool result = result_ptr.ok();
4468     if (!result) {
4469       return on_error(Status::Error(400, "Receive false as result"));
4470     }
4471 
4472     promise_.set_value(Unit());
4473   }
4474 
on_error(Status status)4475   void on_error(Status status) final {
4476     LOG(INFO) << "Receive error for report peer: " << status;
4477     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "ReportPeerQuery");
4478     td_->messages_manager_->reget_dialog_action_bar(dialog_id_, "ReportPeerQuery");
4479     promise_.set_error(std::move(status));
4480   }
4481 };
4482 
4483 class ReportProfilePhotoQuery final : public Td::ResultHandler {
4484   Promise<Unit> promise_;
4485   DialogId dialog_id_;
4486   FileId file_id_;
4487   string file_reference_;
4488   ReportReason report_reason_;
4489 
4490  public:
ReportProfilePhotoQuery(Promise<Unit> && promise)4491   explicit ReportProfilePhotoQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
4492   }
4493 
send(DialogId dialog_id,FileId file_id,tl_object_ptr<telegram_api::InputPhoto> && input_photo,ReportReason && report_reason)4494   void send(DialogId dialog_id, FileId file_id, tl_object_ptr<telegram_api::InputPhoto> &&input_photo,
4495             ReportReason &&report_reason) {
4496     dialog_id_ = dialog_id;
4497     file_id_ = file_id;
4498     file_reference_ = FileManager::extract_file_reference(input_photo);
4499     report_reason_ = std::move(report_reason);
4500 
4501     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
4502     CHECK(input_peer != nullptr);
4503 
4504     send_query(G()->net_query_creator().create(telegram_api::account_reportProfilePhoto(
4505         std::move(input_peer), std::move(input_photo), report_reason_.get_input_report_reason(),
4506         report_reason_.get_message())));
4507   }
4508 
on_result(BufferSlice packet)4509   void on_result(BufferSlice packet) final {
4510     auto result_ptr = fetch_result<telegram_api::account_reportProfilePhoto>(packet);
4511     if (result_ptr.is_error()) {
4512       return on_error(result_ptr.move_as_error());
4513     }
4514 
4515     bool result = result_ptr.ok();
4516     if (!result) {
4517       return on_error(Status::Error(400, "Receive false as result"));
4518     }
4519 
4520     promise_.set_value(Unit());
4521   }
4522 
on_error(Status status)4523   void on_error(Status status) final {
4524     LOG(INFO) << "Receive error for report chat photo: " << status;
4525     if (!td_->auth_manager_->is_bot() && FileReferenceManager::is_file_reference_error(status)) {
4526       VLOG(file_references) << "Receive " << status << " for " << file_id_;
4527       td_->file_manager_->delete_file_reference(file_id_, file_reference_);
4528       td_->file_reference_manager_->repair_file_reference(
4529           file_id_,
4530           PromiseCreator::lambda([dialog_id = dialog_id_, file_id = file_id_, report_reason = std::move(report_reason_),
4531                                   promise = std::move(promise_)](Result<Unit> result) mutable {
4532             if (result.is_error()) {
4533               LOG(INFO) << "Reported photo " << file_id << " is likely to be deleted";
4534               return promise.set_value(Unit());
4535             }
4536             send_closure(G()->messages_manager(), &MessagesManager::report_dialog_photo, dialog_id, file_id,
4537                          std::move(report_reason), std::move(promise));
4538           }));
4539       return;
4540     }
4541 
4542     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "ReportProfilePhotoQuery");
4543     promise_.set_error(std::move(status));
4544   }
4545 };
4546 
4547 class EditPeerFoldersQuery final : public Td::ResultHandler {
4548   Promise<Unit> promise_;
4549   DialogId dialog_id_;
4550 
4551  public:
EditPeerFoldersQuery(Promise<Unit> && promise)4552   explicit EditPeerFoldersQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
4553   }
4554 
send(DialogId dialog_id,FolderId folder_id)4555   void send(DialogId dialog_id, FolderId folder_id) {
4556     dialog_id_ = dialog_id;
4557 
4558     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
4559     CHECK(input_peer != nullptr);
4560 
4561     vector<telegram_api::object_ptr<telegram_api::inputFolderPeer>> input_folder_peers;
4562     input_folder_peers.push_back(
4563         telegram_api::make_object<telegram_api::inputFolderPeer>(std::move(input_peer), folder_id.get()));
4564     send_query(G()->net_query_creator().create(telegram_api::folders_editPeerFolders(std::move(input_folder_peers))));
4565   }
4566 
on_result(BufferSlice packet)4567   void on_result(BufferSlice packet) final {
4568     auto result_ptr = fetch_result<telegram_api::folders_editPeerFolders>(packet);
4569     if (result_ptr.is_error()) {
4570       return on_error(result_ptr.move_as_error());
4571     }
4572 
4573     auto ptr = result_ptr.move_as_ok();
4574     LOG(INFO) << "Receive result for EditPeerFoldersQuery: " << to_string(ptr);
4575     td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
4576   }
4577 
on_error(Status status)4578   void on_error(Status status) final {
4579     if (!td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "EditPeerFoldersQuery")) {
4580       LOG(INFO) << "Receive error for EditPeerFoldersQuery: " << status;
4581     }
4582 
4583     // trying to repair folder ID for this dialog
4584     td_->messages_manager_->get_dialog_info_full(dialog_id_, Auto(), "EditPeerFoldersQuery");
4585 
4586     promise_.set_error(std::move(status));
4587   }
4588 };
4589 
4590 class GetChannelDifferenceQuery final : public Td::ResultHandler {
4591   DialogId dialog_id_;
4592   int32 pts_;
4593   int32 limit_;
4594 
4595  public:
send(DialogId dialog_id,tl_object_ptr<telegram_api::InputChannel> && input_channel,int32 pts,int32 limit,bool force)4596   void send(DialogId dialog_id, tl_object_ptr<telegram_api::InputChannel> &&input_channel, int32 pts, int32 limit,
4597             bool force) {
4598     CHECK(pts >= 0);
4599     dialog_id_ = dialog_id;
4600     pts_ = pts;
4601     limit_ = limit;
4602     CHECK(input_channel != nullptr);
4603 
4604     int32 flags = 0;
4605     if (force) {
4606       flags |= telegram_api::updates_getChannelDifference::FORCE_MASK;
4607     }
4608     send_query(G()->net_query_creator().create(telegram_api::updates_getChannelDifference(
4609         flags, false /*ignored*/, std::move(input_channel), make_tl_object<telegram_api::channelMessagesFilterEmpty>(),
4610         pts, limit)));
4611   }
4612 
on_result(BufferSlice packet)4613   void on_result(BufferSlice packet) final {
4614     auto result_ptr = fetch_result<telegram_api::updates_getChannelDifference>(packet);
4615     if (result_ptr.is_error()) {
4616       return on_error(result_ptr.move_as_error());
4617     }
4618 
4619     td_->messages_manager_->on_get_channel_difference(dialog_id_, pts_, limit_, result_ptr.move_as_ok());
4620   }
4621 
on_error(Status status)4622   void on_error(Status status) final {
4623     if (!td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetChannelDifferenceQuery")) {
4624       LOG(ERROR) << "Receive error for GetChannelDifferenceQuery for " << dialog_id_ << " with pts " << pts_
4625                  << " and limit " << limit_ << ": " << status;
4626     }
4627     td_->messages_manager_->on_get_channel_difference(dialog_id_, pts_, limit_, nullptr);
4628   }
4629 };
4630 
4631 class ResolveUsernameQuery final : public Td::ResultHandler {
4632   Promise<Unit> promise_;
4633   string username_;
4634 
4635  public:
ResolveUsernameQuery(Promise<Unit> && promise)4636   explicit ResolveUsernameQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
4637   }
4638 
send(const string & username)4639   void send(const string &username) {
4640     username_ = username;
4641     send_query(G()->net_query_creator().create(telegram_api::contacts_resolveUsername(username)));
4642   }
4643 
on_result(BufferSlice packet)4644   void on_result(BufferSlice packet) final {
4645     auto result_ptr = fetch_result<telegram_api::contacts_resolveUsername>(packet);
4646     if (result_ptr.is_error()) {
4647       return on_error(result_ptr.move_as_error());
4648     }
4649 
4650     auto ptr = result_ptr.move_as_ok();
4651     LOG(DEBUG) << "Receive result for ResolveUsernameQuery: " << to_string(ptr);
4652     td_->contacts_manager_->on_get_users(std::move(ptr->users_), "ResolveUsernameQuery");
4653     td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "ResolveUsernameQuery");
4654 
4655     td_->messages_manager_->on_resolved_username(username_, DialogId(ptr->peer_));
4656 
4657     promise_.set_value(Unit());
4658   }
4659 
on_error(Status status)4660   void on_error(Status status) final {
4661     if (status.message() == Slice("USERNAME_NOT_OCCUPIED")) {
4662       td_->messages_manager_->drop_username(username_);
4663     }
4664     promise_.set_error(std::move(status));
4665   }
4666 };
4667 
4668 class MessagesManager::UploadMediaCallback final : public FileManager::UploadCallback {
4669  public:
on_progress(FileId file_id)4670   void on_progress(FileId file_id) final {
4671   }
on_upload_ok(FileId file_id,tl_object_ptr<telegram_api::InputFile> input_file)4672   void on_upload_ok(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) final {
4673     send_closure_later(G()->messages_manager(), &MessagesManager::on_upload_media, file_id, std::move(input_file),
4674                        nullptr);
4675   }
on_upload_encrypted_ok(FileId file_id,tl_object_ptr<telegram_api::InputEncryptedFile> input_file)4676   void on_upload_encrypted_ok(FileId file_id, tl_object_ptr<telegram_api::InputEncryptedFile> input_file) final {
4677     send_closure_later(G()->messages_manager(), &MessagesManager::on_upload_media, file_id, nullptr,
4678                        std::move(input_file));
4679   }
on_upload_secure_ok(FileId file_id,tl_object_ptr<telegram_api::InputSecureFile> input_file)4680   void on_upload_secure_ok(FileId file_id, tl_object_ptr<telegram_api::InputSecureFile> input_file) final {
4681     UNREACHABLE();
4682   }
on_upload_error(FileId file_id,Status error)4683   void on_upload_error(FileId file_id, Status error) final {
4684     send_closure_later(G()->messages_manager(), &MessagesManager::on_upload_media_error, file_id, std::move(error));
4685   }
4686 };
4687 
4688 class MessagesManager::UploadThumbnailCallback final : public FileManager::UploadCallback {
4689  public:
on_upload_ok(FileId file_id,tl_object_ptr<telegram_api::InputFile> input_file)4690   void on_upload_ok(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) final {
4691     send_closure_later(G()->messages_manager(), &MessagesManager::on_upload_thumbnail, file_id, std::move(input_file));
4692   }
on_upload_encrypted_ok(FileId file_id,tl_object_ptr<telegram_api::InputEncryptedFile> input_file)4693   void on_upload_encrypted_ok(FileId file_id, tl_object_ptr<telegram_api::InputEncryptedFile> input_file) final {
4694     UNREACHABLE();
4695   }
on_upload_secure_ok(FileId file_id,tl_object_ptr<telegram_api::InputSecureFile> input_file)4696   void on_upload_secure_ok(FileId file_id, tl_object_ptr<telegram_api::InputSecureFile> input_file) final {
4697     UNREACHABLE();
4698   }
on_upload_error(FileId file_id,Status error)4699   void on_upload_error(FileId file_id, Status error) final {
4700     send_closure_later(G()->messages_manager(), &MessagesManager::on_upload_thumbnail, file_id, nullptr);
4701   }
4702 };
4703 
4704 class MessagesManager::UploadDialogPhotoCallback final : public FileManager::UploadCallback {
4705  public:
on_upload_ok(FileId file_id,tl_object_ptr<telegram_api::InputFile> input_file)4706   void on_upload_ok(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) final {
4707     send_closure_later(G()->messages_manager(), &MessagesManager::on_upload_dialog_photo, file_id,
4708                        std::move(input_file));
4709   }
on_upload_encrypted_ok(FileId file_id,tl_object_ptr<telegram_api::InputEncryptedFile> input_file)4710   void on_upload_encrypted_ok(FileId file_id, tl_object_ptr<telegram_api::InputEncryptedFile> input_file) final {
4711     UNREACHABLE();
4712   }
on_upload_secure_ok(FileId file_id,tl_object_ptr<telegram_api::InputSecureFile> input_file)4713   void on_upload_secure_ok(FileId file_id, tl_object_ptr<telegram_api::InputSecureFile> input_file) final {
4714     UNREACHABLE();
4715   }
on_upload_error(FileId file_id,Status error)4716   void on_upload_error(FileId file_id, Status error) final {
4717     send_closure_later(G()->messages_manager(), &MessagesManager::on_upload_dialog_photo_error, file_id,
4718                        std::move(error));
4719   }
4720 };
4721 
4722 class MessagesManager::UploadImportedMessagesCallback final : public FileManager::UploadCallback {
4723  public:
on_upload_ok(FileId file_id,tl_object_ptr<telegram_api::InputFile> input_file)4724   void on_upload_ok(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) final {
4725     send_closure_later(G()->messages_manager(), &MessagesManager::on_upload_imported_messages, file_id,
4726                        std::move(input_file));
4727   }
on_upload_encrypted_ok(FileId file_id,tl_object_ptr<telegram_api::InputEncryptedFile> input_file)4728   void on_upload_encrypted_ok(FileId file_id, tl_object_ptr<telegram_api::InputEncryptedFile> input_file) final {
4729     UNREACHABLE();
4730   }
on_upload_secure_ok(FileId file_id,tl_object_ptr<telegram_api::InputSecureFile> input_file)4731   void on_upload_secure_ok(FileId file_id, tl_object_ptr<telegram_api::InputSecureFile> input_file) final {
4732     UNREACHABLE();
4733   }
on_upload_error(FileId file_id,Status error)4734   void on_upload_error(FileId file_id, Status error) final {
4735     send_closure_later(G()->messages_manager(), &MessagesManager::on_upload_imported_messages_error, file_id,
4736                        std::move(error));
4737   }
4738 };
4739 
4740 class MessagesManager::UploadImportedMessageAttachmentCallback final : public FileManager::UploadCallback {
4741  public:
on_upload_ok(FileId file_id,tl_object_ptr<telegram_api::InputFile> input_file)4742   void on_upload_ok(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) final {
4743     send_closure_later(G()->messages_manager(), &MessagesManager::on_upload_imported_message_attachment, file_id,
4744                        std::move(input_file));
4745   }
on_upload_encrypted_ok(FileId file_id,tl_object_ptr<telegram_api::InputEncryptedFile> input_file)4746   void on_upload_encrypted_ok(FileId file_id, tl_object_ptr<telegram_api::InputEncryptedFile> input_file) final {
4747     UNREACHABLE();
4748   }
on_upload_secure_ok(FileId file_id,tl_object_ptr<telegram_api::InputSecureFile> input_file)4749   void on_upload_secure_ok(FileId file_id, tl_object_ptr<telegram_api::InputSecureFile> input_file) final {
4750     UNREACHABLE();
4751   }
on_upload_error(FileId file_id,Status error)4752   void on_upload_error(FileId file_id, Status error) final {
4753     send_closure_later(G()->messages_manager(), &MessagesManager::on_upload_imported_message_attachment_error, file_id,
4754                        std::move(error));
4755   }
4756 };
4757 
4758 template <class StorerT>
store(StorerT & storer) const4759 void MessagesManager::Message::store(StorerT &storer) const {
4760   using td::store;
4761   bool has_sender = sender_user_id.is_valid();
4762   bool has_edit_date = edit_date > 0;
4763   bool has_random_id = random_id != 0;
4764   bool is_forwarded = forward_info != nullptr;
4765   bool is_reply = reply_to_message_id.is_valid();
4766   bool is_reply_to_random_id = reply_to_random_id != 0;
4767   bool is_via_bot = via_bot_user_id.is_valid();
4768   bool has_view_count = view_count > 0;
4769   bool has_reply_markup = reply_markup != nullptr;
4770   bool has_ttl = ttl != 0;
4771   bool has_author_signature = !author_signature.empty();
4772   bool has_forward_author_signature = is_forwarded && !forward_info->author_signature.empty();
4773   bool has_media_album_id = media_album_id != 0;
4774   bool has_forward_from =
4775       is_forwarded && (forward_info->from_dialog_id.is_valid() || forward_info->from_message_id.is_valid());
4776   bool has_send_date = message_id.is_yet_unsent() && send_date != 0;
4777   bool has_flags2 = true;
4778   bool has_notification_id = notification_id.is_valid();
4779   bool has_forward_sender_name = is_forwarded && !forward_info->sender_name.empty();
4780   bool has_send_error_code = send_error_code != 0;
4781   bool has_real_forward_from = real_forward_from_dialog_id.is_valid() && real_forward_from_message_id.is_valid();
4782   bool has_legacy_layer = legacy_layer != 0;
4783   bool has_restriction_reasons = !restriction_reasons.empty();
4784   bool has_forward_psa_type = is_forwarded && !forward_info->psa_type.empty();
4785   bool has_forward_count = forward_count > 0;
4786   bool has_reply_info = !reply_info.is_empty();
4787   bool has_sender_dialog_id = sender_dialog_id.is_valid();
4788   bool has_reply_in_dialog_id = is_reply && reply_in_dialog_id.is_valid();
4789   bool has_top_thread_message_id = top_thread_message_id.is_valid();
4790   bool has_thread_draft_message = thread_draft_message != nullptr;
4791   bool has_local_thread_message_ids = !local_thread_message_ids.empty();
4792   bool has_linked_top_thread_message_id = linked_top_thread_message_id.is_valid();
4793   bool has_interaction_info_update_date = interaction_info_update_date != 0;
4794   bool has_send_emoji = !send_emoji.empty();
4795   bool is_imported = is_forwarded && forward_info->is_imported;
4796   bool has_ttl_period = ttl_period != 0;
4797   bool has_max_reply_media_timestamp = max_reply_media_timestamp >= 0;
4798   bool are_message_media_timestamp_entities_found = true;
4799   bool has_flags3 = true;
4800   BEGIN_STORE_FLAGS();
4801   STORE_FLAG(is_channel_post);
4802   STORE_FLAG(is_outgoing);
4803   STORE_FLAG(is_failed_to_send);
4804   STORE_FLAG(disable_notification);
4805   STORE_FLAG(contains_mention);
4806   STORE_FLAG(from_background);
4807   STORE_FLAG(disable_web_page_preview);
4808   STORE_FLAG(clear_draft);
4809   STORE_FLAG(have_previous);
4810   STORE_FLAG(have_next);
4811   STORE_FLAG(has_sender);
4812   STORE_FLAG(has_edit_date);
4813   STORE_FLAG(has_random_id);
4814   STORE_FLAG(is_forwarded);
4815   STORE_FLAG(is_reply);
4816   STORE_FLAG(is_reply_to_random_id);
4817   STORE_FLAG(is_via_bot);
4818   STORE_FLAG(has_view_count);
4819   STORE_FLAG(has_reply_markup);
4820   STORE_FLAG(has_ttl);
4821   STORE_FLAG(has_author_signature);
4822   STORE_FLAG(has_forward_author_signature);
4823   STORE_FLAG(had_reply_markup);
4824   STORE_FLAG(contains_unread_mention);
4825   STORE_FLAG(has_media_album_id);
4826   STORE_FLAG(has_forward_from);
4827   STORE_FLAG(in_game_share);
4828   STORE_FLAG(is_content_secret);
4829   STORE_FLAG(has_send_date);
4830   STORE_FLAG(has_flags2);
4831   END_STORE_FLAGS();
4832   if (has_flags2) {
4833     BEGIN_STORE_FLAGS();
4834     STORE_FLAG(has_notification_id);
4835     STORE_FLAG(is_mention_notification_disabled);
4836     STORE_FLAG(had_forward_info);
4837     STORE_FLAG(has_forward_sender_name);
4838     STORE_FLAG(has_send_error_code);
4839     STORE_FLAG(hide_via_bot);
4840     STORE_FLAG(is_bot_start_message);
4841     STORE_FLAG(has_real_forward_from);
4842     STORE_FLAG(has_legacy_layer);
4843     STORE_FLAG(hide_edit_date);
4844     STORE_FLAG(has_restriction_reasons);
4845     STORE_FLAG(is_from_scheduled);
4846     STORE_FLAG(is_copy);
4847     STORE_FLAG(has_forward_psa_type);
4848     STORE_FLAG(has_forward_count);
4849     STORE_FLAG(has_reply_info);
4850     STORE_FLAG(has_sender_dialog_id);
4851     STORE_FLAG(has_reply_in_dialog_id);
4852     STORE_FLAG(has_top_thread_message_id);
4853     STORE_FLAG(has_thread_draft_message);
4854     STORE_FLAG(has_local_thread_message_ids);
4855     STORE_FLAG(has_linked_top_thread_message_id);
4856     STORE_FLAG(is_pinned);
4857     STORE_FLAG(has_interaction_info_update_date);
4858     STORE_FLAG(has_send_emoji);
4859     STORE_FLAG(is_imported);
4860     STORE_FLAG(has_ttl_period);
4861     STORE_FLAG(has_max_reply_media_timestamp);
4862     STORE_FLAG(are_message_media_timestamp_entities_found);
4863     STORE_FLAG(has_flags3);
4864     END_STORE_FLAGS();
4865   }
4866   if (has_flags3) {
4867     BEGIN_STORE_FLAGS();
4868     STORE_FLAG(noforwards);
4869     STORE_FLAG(has_explicit_sender);
4870     END_STORE_FLAGS();
4871   }
4872 
4873   store(message_id, storer);
4874   if (has_sender) {
4875     store(sender_user_id, storer);
4876   }
4877   store(date, storer);
4878   if (has_edit_date) {
4879     store(edit_date, storer);
4880   }
4881   if (has_send_date) {
4882     store(send_date, storer);
4883   }
4884   if (has_random_id) {
4885     store(random_id, storer);
4886   }
4887   if (is_forwarded) {
4888     store(forward_info->sender_user_id, storer);
4889     store(forward_info->date, storer);
4890     store(forward_info->sender_dialog_id, storer);
4891     store(forward_info->message_id, storer);
4892     if (has_forward_author_signature) {
4893       store(forward_info->author_signature, storer);
4894     }
4895     if (has_forward_sender_name) {
4896       store(forward_info->sender_name, storer);
4897     }
4898     if (has_forward_from) {
4899       store(forward_info->from_dialog_id, storer);
4900       store(forward_info->from_message_id, storer);
4901     }
4902     if (has_forward_psa_type) {
4903       store(forward_info->psa_type, storer);
4904     }
4905   }
4906   if (has_real_forward_from) {
4907     store(real_forward_from_dialog_id, storer);
4908     store(real_forward_from_message_id, storer);
4909   }
4910   if (is_reply) {
4911     store(reply_to_message_id, storer);
4912   }
4913   if (is_reply_to_random_id) {
4914     store(reply_to_random_id, storer);
4915   }
4916   if (is_via_bot) {
4917     store(via_bot_user_id, storer);
4918   }
4919   if (has_view_count) {
4920     store(view_count, storer);
4921   }
4922   if (has_forward_count) {
4923     store(forward_count, storer);
4924   }
4925   if (has_reply_info) {
4926     store(reply_info, storer);
4927   }
4928   if (has_ttl) {
4929     store(ttl, storer);
4930     store_time(ttl_expires_at, storer);
4931   }
4932   if (has_send_error_code) {
4933     store(send_error_code, storer);
4934     store(send_error_message, storer);
4935     if (send_error_code == 429) {
4936       store_time(try_resend_at, storer);
4937     }
4938   }
4939   if (has_author_signature) {
4940     store(author_signature, storer);
4941   }
4942   if (has_media_album_id) {
4943     store(media_album_id, storer);
4944   }
4945   if (has_notification_id) {
4946     store(notification_id, storer);
4947   }
4948   if (has_legacy_layer) {
4949     store(legacy_layer, storer);
4950   }
4951   if (has_restriction_reasons) {
4952     store(restriction_reasons, storer);
4953   }
4954   if (has_sender_dialog_id) {
4955     store(sender_dialog_id, storer);
4956   }
4957   if (has_reply_in_dialog_id) {
4958     store(reply_in_dialog_id, storer);
4959   }
4960   if (has_top_thread_message_id) {
4961     store(top_thread_message_id, storer);
4962   }
4963   if (has_thread_draft_message) {
4964     store(thread_draft_message, storer);
4965   }
4966   if (has_local_thread_message_ids) {
4967     store(local_thread_message_ids, storer);
4968   }
4969   if (has_linked_top_thread_message_id) {
4970     store(linked_top_thread_message_id, storer);
4971   }
4972   if (has_interaction_info_update_date) {
4973     store(interaction_info_update_date, storer);
4974   }
4975   if (has_send_emoji) {
4976     store(send_emoji, storer);
4977   }
4978   store_message_content(content.get(), storer);
4979   if (has_reply_markup) {
4980     store(reply_markup, storer);
4981   }
4982   if (has_ttl_period) {
4983     store(ttl_period, storer);
4984   }
4985   if (has_max_reply_media_timestamp) {
4986     store(max_reply_media_timestamp, storer);
4987   }
4988 }
4989 
4990 // do not forget to resolve message dependencies
4991 template <class ParserT>
parse(ParserT & parser)4992 void MessagesManager::Message::parse(ParserT &parser) {
4993   using td::parse;
4994   bool has_sender;
4995   bool has_edit_date;
4996   bool has_random_id;
4997   bool is_forwarded;
4998   bool is_reply;
4999   bool is_reply_to_random_id;
5000   bool is_via_bot;
5001   bool has_view_count;
5002   bool has_reply_markup;
5003   bool has_ttl;
5004   bool has_author_signature;
5005   bool has_forward_author_signature;
5006   bool has_media_album_id;
5007   bool has_forward_from;
5008   bool has_send_date;
5009   bool has_flags2;
5010   bool has_notification_id = false;
5011   bool has_forward_sender_name = false;
5012   bool has_send_error_code = false;
5013   bool has_real_forward_from = false;
5014   bool has_legacy_layer = false;
5015   bool has_restriction_reasons = false;
5016   bool has_forward_psa_type = false;
5017   bool has_forward_count = false;
5018   bool has_reply_info = false;
5019   bool has_sender_dialog_id = false;
5020   bool has_reply_in_dialog_id = false;
5021   bool has_top_thread_message_id = false;
5022   bool has_thread_draft_message = false;
5023   bool has_local_thread_message_ids = false;
5024   bool has_linked_top_thread_message_id = false;
5025   bool has_interaction_info_update_date = false;
5026   bool has_send_emoji = false;
5027   bool is_imported = false;
5028   bool has_ttl_period = false;
5029   bool has_max_reply_media_timestamp = false;
5030   bool has_flags3 = false;
5031   BEGIN_PARSE_FLAGS();
5032   PARSE_FLAG(is_channel_post);
5033   PARSE_FLAG(is_outgoing);
5034   PARSE_FLAG(is_failed_to_send);
5035   PARSE_FLAG(disable_notification);
5036   PARSE_FLAG(contains_mention);
5037   PARSE_FLAG(from_background);
5038   PARSE_FLAG(disable_web_page_preview);
5039   PARSE_FLAG(clear_draft);
5040   PARSE_FLAG(have_previous);
5041   PARSE_FLAG(have_next);
5042   PARSE_FLAG(has_sender);
5043   PARSE_FLAG(has_edit_date);
5044   PARSE_FLAG(has_random_id);
5045   PARSE_FLAG(is_forwarded);
5046   PARSE_FLAG(is_reply);
5047   PARSE_FLAG(is_reply_to_random_id);
5048   PARSE_FLAG(is_via_bot);
5049   PARSE_FLAG(has_view_count);
5050   PARSE_FLAG(has_reply_markup);
5051   PARSE_FLAG(has_ttl);
5052   PARSE_FLAG(has_author_signature);
5053   PARSE_FLAG(has_forward_author_signature);
5054   PARSE_FLAG(had_reply_markup);
5055   PARSE_FLAG(contains_unread_mention);
5056   PARSE_FLAG(has_media_album_id);
5057   PARSE_FLAG(has_forward_from);
5058   PARSE_FLAG(in_game_share);
5059   PARSE_FLAG(is_content_secret);
5060   PARSE_FLAG(has_send_date);
5061   PARSE_FLAG(has_flags2);
5062   END_PARSE_FLAGS();
5063   if (has_flags2) {
5064     BEGIN_PARSE_FLAGS();
5065     PARSE_FLAG(has_notification_id);
5066     PARSE_FLAG(is_mention_notification_disabled);
5067     PARSE_FLAG(had_forward_info);
5068     PARSE_FLAG(has_forward_sender_name);
5069     PARSE_FLAG(has_send_error_code);
5070     PARSE_FLAG(hide_via_bot);
5071     PARSE_FLAG(is_bot_start_message);
5072     PARSE_FLAG(has_real_forward_from);
5073     PARSE_FLAG(has_legacy_layer);
5074     PARSE_FLAG(hide_edit_date);
5075     PARSE_FLAG(has_restriction_reasons);
5076     PARSE_FLAG(is_from_scheduled);
5077     PARSE_FLAG(is_copy);
5078     PARSE_FLAG(has_forward_psa_type);
5079     PARSE_FLAG(has_forward_count);
5080     PARSE_FLAG(has_reply_info);
5081     PARSE_FLAG(has_sender_dialog_id);
5082     PARSE_FLAG(has_reply_in_dialog_id);
5083     PARSE_FLAG(has_top_thread_message_id);
5084     PARSE_FLAG(has_thread_draft_message);
5085     PARSE_FLAG(has_local_thread_message_ids);
5086     PARSE_FLAG(has_linked_top_thread_message_id);
5087     PARSE_FLAG(is_pinned);
5088     PARSE_FLAG(has_interaction_info_update_date);
5089     PARSE_FLAG(has_send_emoji);
5090     PARSE_FLAG(is_imported);
5091     PARSE_FLAG(has_ttl_period);
5092     PARSE_FLAG(has_max_reply_media_timestamp);
5093     PARSE_FLAG(are_media_timestamp_entities_found);
5094     PARSE_FLAG(has_flags3);
5095     END_PARSE_FLAGS();
5096   }
5097   if (has_flags3) {
5098     BEGIN_PARSE_FLAGS();
5099     PARSE_FLAG(noforwards);
5100     PARSE_FLAG(has_explicit_sender);
5101     END_PARSE_FLAGS();
5102   }
5103 
5104   parse(message_id, parser);
5105   random_y = get_random_y(message_id);
5106   if (has_sender) {
5107     parse(sender_user_id, parser);
5108   }
5109   parse(date, parser);
5110   if (has_edit_date) {
5111     parse(edit_date, parser);
5112   }
5113   if (has_send_date) {
5114     CHECK(message_id.is_valid() || message_id.is_valid_scheduled());
5115     CHECK(message_id.is_yet_unsent());
5116     parse(send_date, parser);
5117   } else if (message_id.is_valid() && message_id.is_yet_unsent()) {
5118     send_date = date;  // for backward compatibility
5119   }
5120   if (has_random_id) {
5121     parse(random_id, parser);
5122   }
5123   if (is_forwarded) {
5124     forward_info = make_unique<MessageForwardInfo>();
5125     parse(forward_info->sender_user_id, parser);
5126     parse(forward_info->date, parser);
5127     parse(forward_info->sender_dialog_id, parser);
5128     parse(forward_info->message_id, parser);
5129     if (has_forward_author_signature) {
5130       parse(forward_info->author_signature, parser);
5131     }
5132     if (has_forward_sender_name) {
5133       parse(forward_info->sender_name, parser);
5134     }
5135     if (has_forward_from) {
5136       parse(forward_info->from_dialog_id, parser);
5137       parse(forward_info->from_message_id, parser);
5138     }
5139     if (has_forward_psa_type) {
5140       parse(forward_info->psa_type, parser);
5141     }
5142     forward_info->is_imported = is_imported;
5143   }
5144   if (has_real_forward_from) {
5145     parse(real_forward_from_dialog_id, parser);
5146     parse(real_forward_from_message_id, parser);
5147   }
5148   if (is_reply) {
5149     parse(reply_to_message_id, parser);
5150   }
5151   if (is_reply_to_random_id) {
5152     parse(reply_to_random_id, parser);
5153   }
5154   if (is_via_bot) {
5155     parse(via_bot_user_id, parser);
5156   }
5157   if (has_view_count) {
5158     parse(view_count, parser);
5159   }
5160   if (has_forward_count) {
5161     parse(forward_count, parser);
5162   }
5163   if (has_reply_info) {
5164     parse(reply_info, parser);
5165   }
5166   if (has_ttl) {
5167     parse(ttl, parser);
5168     parse_time(ttl_expires_at, parser);
5169   }
5170   if (has_send_error_code) {
5171     parse(send_error_code, parser);
5172     parse(send_error_message, parser);
5173     if (send_error_code == 429) {
5174       parse_time(try_resend_at, parser);
5175     }
5176   }
5177   if (has_author_signature) {
5178     parse(author_signature, parser);
5179   }
5180   if (has_media_album_id) {
5181     parse(media_album_id, parser);
5182   }
5183   if (has_notification_id) {
5184     parse(notification_id, parser);
5185   }
5186   if (has_legacy_layer) {
5187     parse(legacy_layer, parser);
5188   }
5189   if (has_restriction_reasons) {
5190     parse(restriction_reasons, parser);
5191   }
5192   if (has_sender_dialog_id) {
5193     parse(sender_dialog_id, parser);
5194   }
5195   if (has_reply_in_dialog_id) {
5196     parse(reply_in_dialog_id, parser);
5197   }
5198   if (has_top_thread_message_id) {
5199     parse(top_thread_message_id, parser);
5200   }
5201   if (has_thread_draft_message) {
5202     parse(thread_draft_message, parser);
5203   }
5204   if (has_local_thread_message_ids) {
5205     parse(local_thread_message_ids, parser);
5206   }
5207   if (has_linked_top_thread_message_id) {
5208     parse(linked_top_thread_message_id, parser);
5209   }
5210   if (has_interaction_info_update_date) {
5211     parse(interaction_info_update_date, parser);
5212   }
5213   if (has_send_emoji) {
5214     parse(send_emoji, parser);
5215   }
5216   parse_message_content(content, parser);
5217   if (has_reply_markup) {
5218     parse(reply_markup, parser);
5219   }
5220   if (has_ttl_period) {
5221     parse(ttl_period, parser);
5222   }
5223   if (has_max_reply_media_timestamp) {
5224     parse(max_reply_media_timestamp, parser);
5225   }
5226 
5227   CHECK(content != nullptr);
5228   is_content_secret |=
5229       is_secret_message_content(ttl, content->get_type());  // repair is_content_secret for old messages
5230   if (hide_edit_date && content->get_type() == MessageContentType::LiveLocation) {
5231     hide_edit_date = false;
5232   }
5233 }
5234 
5235 template <class StorerT>
store(StorerT & storer) const5236 void MessagesManager::NotificationGroupInfo::store(StorerT &storer) const {
5237   using td::store;
5238   store(group_id, storer);
5239   store(last_notification_date, storer);
5240   store(last_notification_id, storer);
5241   store(max_removed_notification_id, storer);
5242   store(max_removed_message_id, storer);
5243 }
5244 
5245 template <class ParserT>
parse(ParserT & parser)5246 void MessagesManager::NotificationGroupInfo::parse(ParserT &parser) {
5247   using td::parse;
5248   parse(group_id, parser);
5249   parse(last_notification_date, parser);
5250   parse(last_notification_id, parser);
5251   parse(max_removed_notification_id, parser);
5252   if (parser.version() >= static_cast<int32>(Version::AddNotificationGroupInfoMaxRemovedMessageId)) {
5253     parse(max_removed_message_id, parser);
5254   }
5255 }
5256 
5257 template <class StorerT>
store(StorerT & storer) const5258 void MessagesManager::Dialog::store(StorerT &storer) const {
5259   using td::store;
5260   const Message *last_database_message = nullptr;
5261   if (last_database_message_id.is_valid()) {
5262     last_database_message = get_message(this, last_database_message_id);
5263   }
5264 
5265   auto dialog_type = dialog_id.get_type();
5266   bool has_draft_message = draft_message != nullptr;
5267   bool has_last_database_message = last_database_message != nullptr;
5268   bool has_first_database_message_id = first_database_message_id.is_valid();
5269   bool has_first_database_message_id_by_index = true;
5270   bool has_message_count_by_index = true;
5271   bool has_client_data = !client_data.empty();
5272   bool has_last_read_all_mentions_message_id = last_read_all_mentions_message_id.is_valid();
5273   bool has_max_unavailable_message_id = max_unavailable_message_id.is_valid();
5274   bool has_local_unread_count = local_unread_count != 0;
5275   bool has_deleted_last_message = delete_last_message_date > 0;
5276   bool has_last_clear_history_message_id = last_clear_history_message_id.is_valid();
5277   bool has_last_database_message_id = !has_last_database_message && last_database_message_id.is_valid();
5278   bool has_message_notification_group =
5279       message_notification_group.group_id.is_valid() && !message_notification_group.try_reuse;
5280   bool has_mention_notification_group =
5281       mention_notification_group.group_id.is_valid() && !mention_notification_group.try_reuse;
5282   bool has_new_secret_chat_notification_id = new_secret_chat_notification_id.is_valid();
5283   bool has_pinned_message_notification = pinned_message_notification_message_id.is_valid();
5284   bool has_last_pinned_message_id = last_pinned_message_id.is_valid();
5285   bool has_flags2 = true;
5286   bool has_max_notification_message_id =
5287       max_notification_message_id.is_valid() && max_notification_message_id > last_new_message_id;
5288   bool has_folder_id = folder_id != FolderId();
5289   bool has_pending_read_channel_inbox = pending_read_channel_inbox_pts != 0;
5290   bool has_last_yet_unsent_message = last_message_id.is_valid() && last_message_id.is_yet_unsent();
5291   bool has_active_group_call_id = active_group_call_id.is_valid();
5292   bool has_message_ttl_setting = !message_ttl_setting.is_empty();
5293   bool has_default_join_group_call_as_dialog_id = default_join_group_call_as_dialog_id.is_valid();
5294   bool store_has_bots = dialog_type == DialogType::Chat || dialog_type == DialogType::Channel;
5295   bool has_theme_name = !theme_name.empty();
5296   bool has_flags3 = true;
5297   bool has_pending_join_requests = pending_join_request_count != 0;
5298   bool has_action_bar = action_bar != nullptr;
5299   bool has_default_send_message_as_dialog_id = default_send_message_as_dialog_id.is_valid();
5300   BEGIN_STORE_FLAGS();
5301   STORE_FLAG(has_draft_message);
5302   STORE_FLAG(has_last_database_message);
5303   STORE_FLAG(false);  // legacy_know_can_report_spam
5304   STORE_FLAG(false);  // action_bar->can_report_spam
5305   STORE_FLAG(has_first_database_message_id);
5306   STORE_FLAG(false);  // legacy_is_pinned
5307   STORE_FLAG(has_first_database_message_id_by_index);
5308   STORE_FLAG(has_message_count_by_index);
5309   STORE_FLAG(has_client_data);
5310   STORE_FLAG(need_restore_reply_markup);
5311   STORE_FLAG(have_full_history);
5312   STORE_FLAG(has_last_read_all_mentions_message_id);
5313   STORE_FLAG(has_max_unavailable_message_id);
5314   STORE_FLAG(is_last_read_inbox_message_id_inited);
5315   STORE_FLAG(is_last_read_outbox_message_id_inited);
5316   STORE_FLAG(has_local_unread_count);
5317   STORE_FLAG(has_deleted_last_message);
5318   STORE_FLAG(has_last_clear_history_message_id);
5319   STORE_FLAG(is_last_message_deleted_locally);
5320   STORE_FLAG(has_contact_registered_message);
5321   STORE_FLAG(has_last_database_message_id);
5322   STORE_FLAG(need_repair_server_unread_count);
5323   STORE_FLAG(is_marked_as_unread);
5324   STORE_FLAG(has_message_notification_group);
5325   STORE_FLAG(has_mention_notification_group);
5326   STORE_FLAG(has_new_secret_chat_notification_id);
5327   STORE_FLAG(has_pinned_message_notification);
5328   STORE_FLAG(has_last_pinned_message_id);
5329   STORE_FLAG(is_last_pinned_message_id_inited);
5330   STORE_FLAG(has_flags2);
5331   END_STORE_FLAGS();
5332 
5333   store(dialog_id, storer);  // must be stored at offset 4
5334 
5335   if (has_flags2) {
5336     BEGIN_STORE_FLAGS();
5337     STORE_FLAG(has_max_notification_message_id);
5338     STORE_FLAG(has_folder_id);
5339     STORE_FLAG(is_folder_id_inited);
5340     STORE_FLAG(has_pending_read_channel_inbox);
5341     STORE_FLAG(know_action_bar);
5342     STORE_FLAG(false);  // action_bar->can_add_contact
5343     STORE_FLAG(false);  // action_bar->can_block_user
5344     STORE_FLAG(false);  // action_bar->can_share_phone_number
5345     STORE_FLAG(false);  // action_bar->can_report_location
5346     STORE_FLAG(has_scheduled_server_messages);
5347     STORE_FLAG(has_scheduled_database_messages);
5348     STORE_FLAG(need_repair_channel_server_unread_count);
5349     STORE_FLAG(false);  // action_bar->can_unarchive
5350     STORE_FLAG(false);  // action_bar_has_distance
5351     STORE_FLAG(has_outgoing_messages);
5352     STORE_FLAG(has_last_yet_unsent_message);
5353     STORE_FLAG(is_blocked);
5354     STORE_FLAG(is_is_blocked_inited);
5355     STORE_FLAG(has_active_group_call);
5356     STORE_FLAG(is_group_call_empty);
5357     STORE_FLAG(has_active_group_call_id);
5358     STORE_FLAG(false);  // action_bar->can_invite_members
5359     STORE_FLAG(has_message_ttl_setting);
5360     STORE_FLAG(is_message_ttl_setting_inited);
5361     STORE_FLAG(has_default_join_group_call_as_dialog_id);
5362     STORE_FLAG(store_has_bots ? has_bots : false);
5363     STORE_FLAG(store_has_bots ? is_has_bots_inited : false);
5364     STORE_FLAG(is_theme_name_inited);
5365     STORE_FLAG(has_theme_name);
5366     STORE_FLAG(has_flags3);
5367     END_STORE_FLAGS();
5368   }
5369   if (has_flags3) {
5370     BEGIN_STORE_FLAGS();
5371     STORE_FLAG(has_pending_join_requests);
5372     STORE_FLAG(need_repair_action_bar);
5373     STORE_FLAG(has_action_bar);
5374     STORE_FLAG(has_default_send_message_as_dialog_id);
5375     END_STORE_FLAGS();
5376   }
5377 
5378   store(last_new_message_id, storer);
5379   store(server_unread_count, storer);
5380   if (has_local_unread_count) {
5381     store(local_unread_count, storer);
5382   }
5383   store(last_read_inbox_message_id, storer);
5384   store(last_read_outbox_message_id, storer);
5385   store(reply_markup_message_id, storer);
5386   store(notification_settings, storer);
5387   if (has_draft_message) {
5388     store(draft_message, storer);
5389   }
5390   store(last_clear_history_date, storer);
5391   store(order, storer);
5392   if (has_last_database_message) {
5393     store(*last_database_message, storer);
5394   }
5395   if (has_first_database_message_id) {
5396     store(first_database_message_id, storer);
5397   }
5398   if (has_deleted_last_message) {
5399     store(delete_last_message_date, storer);
5400     store(deleted_last_message_id, storer);
5401   }
5402   if (has_last_clear_history_message_id) {
5403     store(last_clear_history_message_id, storer);
5404   }
5405 
5406   if (has_first_database_message_id_by_index) {
5407     store(static_cast<int32>(first_database_message_id_by_index.size()), storer);
5408     for (auto first_message_id : first_database_message_id_by_index) {
5409       store(first_message_id, storer);
5410     }
5411   }
5412   if (has_message_count_by_index) {
5413     store(static_cast<int32>(message_count_by_index.size()), storer);
5414     for (auto message_count : message_count_by_index) {
5415       store(message_count, storer);
5416     }
5417   }
5418   if (has_client_data) {
5419     store(client_data, storer);
5420   }
5421   if (has_last_read_all_mentions_message_id) {
5422     store(last_read_all_mentions_message_id, storer);
5423   }
5424   if (has_max_unavailable_message_id) {
5425     store(max_unavailable_message_id, storer);
5426   }
5427   if (has_last_database_message_id) {
5428     store(last_database_message_id, storer);
5429   }
5430   if (has_message_notification_group) {
5431     store(message_notification_group, storer);
5432   }
5433   if (has_mention_notification_group) {
5434     store(mention_notification_group, storer);
5435   }
5436   if (has_new_secret_chat_notification_id) {
5437     store(new_secret_chat_notification_id, storer);
5438   }
5439   if (has_pinned_message_notification) {
5440     store(pinned_message_notification_message_id, storer);
5441   }
5442   if (has_last_pinned_message_id) {
5443     store(last_pinned_message_id, storer);
5444   }
5445   if (has_max_notification_message_id) {
5446     store(max_notification_message_id, storer);
5447   }
5448   if (has_folder_id) {
5449     store(folder_id, storer);
5450   }
5451   if (has_pending_read_channel_inbox) {
5452     store(pending_read_channel_inbox_pts, storer);
5453     store(pending_read_channel_inbox_max_message_id, storer);
5454     store(pending_read_channel_inbox_server_unread_count, storer);
5455   }
5456   if (has_active_group_call_id) {
5457     store(active_group_call_id, storer);
5458   }
5459   if (has_message_ttl_setting) {
5460     store(message_ttl_setting, storer);
5461   }
5462   if (has_default_join_group_call_as_dialog_id) {
5463     store(default_join_group_call_as_dialog_id, storer);
5464   }
5465   if (has_theme_name) {
5466     store(theme_name, storer);
5467   }
5468   if (has_pending_join_requests) {
5469     store(pending_join_request_count, storer);
5470     store(pending_join_request_user_ids, storer);
5471   }
5472   if (has_action_bar) {
5473     store(action_bar, storer);
5474   }
5475   if (has_default_send_message_as_dialog_id) {
5476     store(default_send_message_as_dialog_id, storer);
5477   }
5478 }
5479 
5480 // do not forget to resolve dialog dependencies including dependencies of last_message
5481 template <class ParserT>
parse(ParserT & parser)5482 void MessagesManager::Dialog::parse(ParserT &parser) {
5483   using td::parse;
5484   bool has_draft_message;
5485   bool has_last_database_message;
5486   bool legacy_know_can_report_spam;
5487   bool has_first_database_message_id;
5488   bool legacy_is_pinned;
5489   bool has_first_database_message_id_by_index;
5490   bool has_message_count_by_index;
5491   bool has_client_data;
5492   bool has_last_read_all_mentions_message_id;
5493   bool has_max_unavailable_message_id;
5494   bool has_local_unread_count;
5495   bool has_deleted_last_message;
5496   bool has_last_clear_history_message_id;
5497   bool has_last_database_message_id;
5498   bool has_message_notification_group;
5499   bool has_mention_notification_group;
5500   bool has_new_secret_chat_notification_id;
5501   bool has_pinned_message_notification;
5502   bool has_last_pinned_message_id;
5503   bool has_flags2;
5504   bool has_max_notification_message_id = false;
5505   bool has_folder_id = false;
5506   bool has_pending_read_channel_inbox = false;
5507   bool has_active_group_call_id = false;
5508   bool has_message_ttl_setting = false;
5509   bool has_default_join_group_call_as_dialog_id = false;
5510   bool has_theme_name = false;
5511   bool has_flags3 = false;
5512   bool has_pending_join_requests = false;
5513   bool action_bar_can_report_spam = false;
5514   bool action_bar_can_add_contact = false;
5515   bool action_bar_can_block_user = false;
5516   bool action_bar_can_share_phone_number = false;
5517   bool action_bar_can_report_location = false;
5518   bool action_bar_can_unarchive = false;
5519   bool action_bar_has_distance = false;
5520   bool action_bar_can_invite_members = false;
5521   bool has_action_bar = false;
5522   bool has_default_send_message_as_dialog_id = false;
5523   BEGIN_PARSE_FLAGS();
5524   PARSE_FLAG(has_draft_message);
5525   PARSE_FLAG(has_last_database_message);
5526   PARSE_FLAG(legacy_know_can_report_spam);
5527   PARSE_FLAG(action_bar_can_report_spam);
5528   PARSE_FLAG(has_first_database_message_id);
5529   PARSE_FLAG(legacy_is_pinned);
5530   PARSE_FLAG(has_first_database_message_id_by_index);
5531   PARSE_FLAG(has_message_count_by_index);
5532   PARSE_FLAG(has_client_data);
5533   PARSE_FLAG(need_restore_reply_markup);
5534   PARSE_FLAG(have_full_history);
5535   PARSE_FLAG(has_last_read_all_mentions_message_id);
5536   PARSE_FLAG(has_max_unavailable_message_id);
5537   PARSE_FLAG(is_last_read_inbox_message_id_inited);
5538   PARSE_FLAG(is_last_read_outbox_message_id_inited);
5539   PARSE_FLAG(has_local_unread_count);
5540   PARSE_FLAG(has_deleted_last_message);
5541   PARSE_FLAG(has_last_clear_history_message_id);
5542   PARSE_FLAG(is_last_message_deleted_locally);
5543   PARSE_FLAG(has_contact_registered_message);
5544   PARSE_FLAG(has_last_database_message_id);
5545   PARSE_FLAG(need_repair_server_unread_count);
5546   PARSE_FLAG(is_marked_as_unread);
5547   PARSE_FLAG(has_message_notification_group);
5548   PARSE_FLAG(has_mention_notification_group);
5549   PARSE_FLAG(has_new_secret_chat_notification_id);
5550   PARSE_FLAG(has_pinned_message_notification);
5551   PARSE_FLAG(has_last_pinned_message_id);
5552   PARSE_FLAG(is_last_pinned_message_id_inited);
5553   PARSE_FLAG(has_flags2);
5554   END_PARSE_FLAGS();
5555 
5556   parse(dialog_id, parser);  // must be stored at offset 4
5557 
5558   if (has_flags2) {
5559     BEGIN_PARSE_FLAGS();
5560     PARSE_FLAG(has_max_notification_message_id);
5561     PARSE_FLAG(has_folder_id);
5562     PARSE_FLAG(is_folder_id_inited);
5563     PARSE_FLAG(has_pending_read_channel_inbox);
5564     PARSE_FLAG(know_action_bar);
5565     PARSE_FLAG(action_bar_can_add_contact);
5566     PARSE_FLAG(action_bar_can_block_user);
5567     PARSE_FLAG(action_bar_can_share_phone_number);
5568     PARSE_FLAG(action_bar_can_report_location);
5569     PARSE_FLAG(has_scheduled_server_messages);
5570     PARSE_FLAG(has_scheduled_database_messages);
5571     PARSE_FLAG(need_repair_channel_server_unread_count);
5572     PARSE_FLAG(action_bar_can_unarchive);
5573     PARSE_FLAG(action_bar_has_distance);
5574     PARSE_FLAG(has_outgoing_messages);
5575     PARSE_FLAG(had_last_yet_unsent_message);
5576     PARSE_FLAG(is_blocked);
5577     PARSE_FLAG(is_is_blocked_inited);
5578     PARSE_FLAG(has_active_group_call);
5579     PARSE_FLAG(is_group_call_empty);
5580     PARSE_FLAG(has_active_group_call_id);
5581     PARSE_FLAG(action_bar_can_invite_members);
5582     PARSE_FLAG(has_message_ttl_setting);
5583     PARSE_FLAG(is_message_ttl_setting_inited);
5584     PARSE_FLAG(has_default_join_group_call_as_dialog_id);
5585     PARSE_FLAG(has_bots);
5586     PARSE_FLAG(is_has_bots_inited);
5587     PARSE_FLAG(is_theme_name_inited);
5588     PARSE_FLAG(has_theme_name);
5589     PARSE_FLAG(has_flags3);
5590     END_PARSE_FLAGS();
5591   } else {
5592     is_folder_id_inited = false;
5593     has_scheduled_server_messages = false;
5594     has_scheduled_database_messages = false;
5595     need_repair_channel_server_unread_count = false;
5596     has_outgoing_messages = false;
5597     had_last_yet_unsent_message = false;
5598     is_blocked = false;
5599     is_is_blocked_inited = false;
5600     has_active_group_call = false;
5601     is_group_call_empty = false;
5602     is_message_ttl_setting_inited = false;
5603     has_bots = false;
5604     is_has_bots_inited = false;
5605     is_theme_name_inited = false;
5606   }
5607   if (has_flags3) {
5608     BEGIN_PARSE_FLAGS();
5609     PARSE_FLAG(has_pending_join_requests);
5610     PARSE_FLAG(need_repair_action_bar);
5611     PARSE_FLAG(has_action_bar);
5612     PARSE_FLAG(has_default_send_message_as_dialog_id);
5613     END_PARSE_FLAGS();
5614   } else {
5615     need_repair_action_bar = false;
5616   }
5617 
5618   parse(last_new_message_id, parser);
5619   parse(server_unread_count, parser);
5620   if (has_local_unread_count) {
5621     parse(local_unread_count, parser);
5622   }
5623   parse(last_read_inbox_message_id, parser);
5624   if (last_read_inbox_message_id.is_valid()) {
5625     is_last_read_inbox_message_id_inited = true;
5626   }
5627   parse(last_read_outbox_message_id, parser);
5628   if (last_read_outbox_message_id.is_valid()) {
5629     is_last_read_outbox_message_id_inited = true;
5630   }
5631   parse(reply_markup_message_id, parser);
5632   parse(notification_settings, parser);
5633   if (has_draft_message) {
5634     parse(draft_message, parser);
5635   }
5636   parse(last_clear_history_date, parser);
5637   parse(order, parser);
5638   if (has_last_database_message) {
5639     parse(messages, parser);
5640   }
5641   if (has_first_database_message_id) {
5642     parse(first_database_message_id, parser);
5643   }
5644   if (legacy_is_pinned) {
5645     int64 legacy_pinned_order;
5646     parse(legacy_pinned_order, parser);
5647   }
5648   if (has_deleted_last_message) {
5649     parse(delete_last_message_date, parser);
5650     parse(deleted_last_message_id, parser);
5651   }
5652   if (has_last_clear_history_message_id) {
5653     parse(last_clear_history_message_id, parser);
5654   }
5655 
5656   if (has_first_database_message_id_by_index) {
5657     int32 size;
5658     parse(size, parser);
5659     if (size < 0) {
5660       // the log event is broken
5661       // it should be impossible, but has happenned at least once
5662       parser.set_error("Wrong first_database_message_id_by_index table size");
5663       return;
5664     }
5665     LOG_CHECK(static_cast<size_t>(size) <= first_database_message_id_by_index.size())
5666         << size << " " << first_database_message_id_by_index.size();
5667     for (int32 i = 0; i < size; i++) {
5668       parse(first_database_message_id_by_index[i], parser);
5669     }
5670   }
5671   if (has_message_count_by_index) {
5672     int32 size;
5673     parse(size, parser);
5674     if (size < 0) {
5675       // the log event is broken
5676       // it should be impossible, but has happenned at least once
5677       parser.set_error("Wrong message_count_by_index table size");
5678       return;
5679     }
5680     LOG_CHECK(static_cast<size_t>(size) <= message_count_by_index.size())
5681         << size << " " << message_count_by_index.size();
5682     for (int32 i = 0; i < size; i++) {
5683       parse(message_count_by_index[i], parser);
5684     }
5685   }
5686   unread_mention_count = message_count_by_index[message_search_filter_index(MessageSearchFilter::UnreadMention)];
5687   LOG(INFO) << "Set unread mention message count in " << dialog_id << " to " << unread_mention_count;
5688   if (unread_mention_count < 0) {
5689     unread_mention_count = 0;
5690   }
5691   if (has_client_data) {
5692     parse(client_data, parser);
5693   }
5694   if (has_last_read_all_mentions_message_id) {
5695     parse(last_read_all_mentions_message_id, parser);
5696   }
5697   if (has_max_unavailable_message_id) {
5698     parse(max_unavailable_message_id, parser);
5699   }
5700   if (has_last_database_message_id) {
5701     parse(last_database_message_id, parser);
5702   }
5703   if (has_message_notification_group) {
5704     parse(message_notification_group, parser);
5705   }
5706   if (has_mention_notification_group) {
5707     parse(mention_notification_group, parser);
5708   }
5709   if (has_new_secret_chat_notification_id) {
5710     parse(new_secret_chat_notification_id, parser);
5711   }
5712   if (has_pinned_message_notification) {
5713     parse(pinned_message_notification_message_id, parser);
5714   }
5715   if (has_last_pinned_message_id) {
5716     parse(last_pinned_message_id, parser);
5717   }
5718   if (has_max_notification_message_id) {
5719     parse(max_notification_message_id, parser);
5720   }
5721   if (has_folder_id) {
5722     parse(folder_id, parser);
5723   }
5724   if (has_pending_read_channel_inbox) {
5725     parse(pending_read_channel_inbox_pts, parser);
5726     parse(pending_read_channel_inbox_max_message_id, parser);
5727     parse(pending_read_channel_inbox_server_unread_count, parser);
5728   }
5729   int32 action_bar_distance = -1;
5730   if (action_bar_has_distance) {
5731     parse(action_bar_distance, parser);
5732   }
5733   if (has_active_group_call_id) {
5734     parse(active_group_call_id, parser);
5735   }
5736   if (has_message_ttl_setting) {
5737     parse(message_ttl_setting, parser);
5738   }
5739   if (has_default_join_group_call_as_dialog_id) {
5740     parse(default_join_group_call_as_dialog_id, parser);
5741   }
5742   if (has_theme_name) {
5743     parse(theme_name, parser);
5744   }
5745   if (has_pending_join_requests) {
5746     parse(pending_join_request_count, parser);
5747     parse(pending_join_request_user_ids, parser);
5748   }
5749   if (has_action_bar) {
5750     parse(action_bar, parser);
5751   }
5752   if (has_default_send_message_as_dialog_id) {
5753     parse(default_send_message_as_dialog_id, parser);
5754   }
5755 
5756   (void)legacy_know_can_report_spam;
5757   if (know_action_bar && !has_action_bar) {
5758     action_bar = DialogActionBar::create(
5759         action_bar_can_report_spam, action_bar_can_add_contact, action_bar_can_block_user,
5760         action_bar_can_share_phone_number, action_bar_can_report_location, action_bar_can_unarchive,
5761         has_outgoing_messages ? -1 : action_bar_distance, action_bar_can_invite_members, string(), false, 0);
5762   }
5763 }
5764 
5765 template <class StorerT>
store(StorerT & storer) const5766 void MessagesManager::CallsDbState::store(StorerT &storer) const {
5767   using td::store;
5768   store(static_cast<int32>(first_calls_database_message_id_by_index.size()), storer);
5769   for (auto first_message_id : first_calls_database_message_id_by_index) {
5770     store(first_message_id, storer);
5771   }
5772   store(static_cast<int32>(message_count_by_index.size()), storer);
5773   for (auto message_count : message_count_by_index) {
5774     store(message_count, storer);
5775   }
5776 }
5777 
5778 template <class ParserT>
parse(ParserT & parser)5779 void MessagesManager::CallsDbState::parse(ParserT &parser) {
5780   using td::parse;
5781   int32 size;
5782   parse(size, parser);
5783   LOG_CHECK(static_cast<size_t>(size) <= first_calls_database_message_id_by_index.size())
5784       << size << " " << first_calls_database_message_id_by_index.size();
5785   for (int32 i = 0; i < size; i++) {
5786     parse(first_calls_database_message_id_by_index[i], parser);
5787   }
5788   parse(size, parser);
5789   LOG_CHECK(static_cast<size_t>(size) <= message_count_by_index.size()) << size << " " << message_count_by_index.size();
5790   for (int32 i = 0; i < size; i++) {
5791     parse(message_count_by_index[i], parser);
5792   }
5793 }
5794 
load_calls_db_state()5795 void MessagesManager::load_calls_db_state() {
5796   if (!G()->parameters().use_message_db) {
5797     return;
5798   }
5799   std::fill(calls_db_state_.message_count_by_index.begin(), calls_db_state_.message_count_by_index.end(), -1);
5800   auto value = G()->td_db()->get_sqlite_sync_pmc()->get("calls_db_state");
5801   if (value.empty()) {
5802     return;
5803   }
5804   log_event_parse(calls_db_state_, value).ensure();
5805   LOG(INFO) << "Save calls database state " << calls_db_state_.first_calls_database_message_id_by_index[0] << " ("
5806             << calls_db_state_.message_count_by_index[0] << ") "
5807             << calls_db_state_.first_calls_database_message_id_by_index[1] << " ("
5808             << calls_db_state_.message_count_by_index[1] << ")";
5809 }
5810 
save_calls_db_state()5811 void MessagesManager::save_calls_db_state() {
5812   if (!G()->parameters().use_message_db) {
5813     return;
5814   }
5815 
5816   LOG(INFO) << "Save calls database state " << calls_db_state_.first_calls_database_message_id_by_index[0] << " ("
5817             << calls_db_state_.message_count_by_index[0] << ") "
5818             << calls_db_state_.first_calls_database_message_id_by_index[1] << " ("
5819             << calls_db_state_.message_count_by_index[1] << ")";
5820   G()->td_db()->get_sqlite_pmc()->set("calls_db_state", log_event_store(calls_db_state_).as_slice().str(), Auto());
5821 }
5822 
~Dialog()5823 MessagesManager::Dialog::~Dialog() {
5824   if (!G()->close_flag()) {
5825     LOG(ERROR) << "Destroy " << dialog_id;
5826   }
5827 }
5828 
MessagesManager(Td * td,ActorShared<> parent)5829 MessagesManager::MessagesManager(Td *td, ActorShared<> parent)
5830     : recently_found_dialogs_{td, "recently_found", MAX_RECENT_DIALOGS}
5831     , recently_opened_dialogs_{td, "recently_opened", MAX_RECENT_DIALOGS}
5832     , td_(td)
5833     , parent_(std::move(parent)) {
5834   upload_media_callback_ = std::make_shared<UploadMediaCallback>();
5835   upload_thumbnail_callback_ = std::make_shared<UploadThumbnailCallback>();
5836   upload_dialog_photo_callback_ = std::make_shared<UploadDialogPhotoCallback>();
5837   upload_imported_messages_callback_ = std::make_shared<UploadImportedMessagesCallback>();
5838   upload_imported_message_attachment_callback_ = std::make_shared<UploadImportedMessageAttachmentCallback>();
5839 
5840   channel_get_difference_timeout_.set_callback(on_channel_get_difference_timeout_callback);
5841   channel_get_difference_timeout_.set_callback_data(static_cast<void *>(this));
5842 
5843   channel_get_difference_retry_timeout_.set_callback(on_channel_get_difference_timeout_callback);
5844   channel_get_difference_retry_timeout_.set_callback_data(static_cast<void *>(this));
5845 
5846   pending_message_views_timeout_.set_callback(on_pending_message_views_timeout_callback);
5847   pending_message_views_timeout_.set_callback_data(static_cast<void *>(this));
5848 
5849   pending_message_live_location_view_timeout_.set_callback(on_pending_message_live_location_view_timeout_callback);
5850   pending_message_live_location_view_timeout_.set_callback_data(static_cast<void *>(this));
5851 
5852   pending_draft_message_timeout_.set_callback(on_pending_draft_message_timeout_callback);
5853   pending_draft_message_timeout_.set_callback_data(static_cast<void *>(this));
5854 
5855   pending_read_history_timeout_.set_callback(on_pending_read_history_timeout_callback);
5856   pending_read_history_timeout_.set_callback_data(static_cast<void *>(this));
5857 
5858   pending_updated_dialog_timeout_.set_callback(on_pending_updated_dialog_timeout_callback);
5859   pending_updated_dialog_timeout_.set_callback_data(static_cast<void *>(this));
5860 
5861   pending_unload_dialog_timeout_.set_callback(on_pending_unload_dialog_timeout_callback);
5862   pending_unload_dialog_timeout_.set_callback_data(static_cast<void *>(this));
5863 
5864   dialog_unmute_timeout_.set_callback(on_dialog_unmute_timeout_callback);
5865   dialog_unmute_timeout_.set_callback_data(static_cast<void *>(this));
5866 
5867   pending_send_dialog_action_timeout_.set_callback(on_pending_send_dialog_action_timeout_callback);
5868   pending_send_dialog_action_timeout_.set_callback_data(static_cast<void *>(this));
5869 
5870   active_dialog_action_timeout_.set_callback(on_active_dialog_action_timeout_callback);
5871   active_dialog_action_timeout_.set_callback_data(static_cast<void *>(this));
5872 
5873   update_dialog_online_member_count_timeout_.set_callback(on_update_dialog_online_member_count_timeout_callback);
5874   update_dialog_online_member_count_timeout_.set_callback_data(static_cast<void *>(this));
5875 
5876   preload_folder_dialog_list_timeout_.set_callback(on_preload_folder_dialog_list_timeout_callback);
5877   preload_folder_dialog_list_timeout_.set_callback_data(static_cast<void *>(this));
5878 
5879   sequence_dispatcher_ = create_actor<MultiSequenceDispatcher>("multi sequence dispatcher");
5880 }
5881 
5882 MessagesManager::~MessagesManager() = default;
5883 
on_channel_get_difference_timeout_callback(void * messages_manager_ptr,int64 dialog_id_int)5884 void MessagesManager::on_channel_get_difference_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int) {
5885   if (G()->close_flag()) {
5886     return;
5887   }
5888 
5889   auto messages_manager = static_cast<MessagesManager *>(messages_manager_ptr);
5890   send_closure_later(messages_manager->actor_id(messages_manager), &MessagesManager::on_channel_get_difference_timeout,
5891                      DialogId(dialog_id_int));
5892 }
5893 
on_pending_message_views_timeout_callback(void * messages_manager_ptr,int64 dialog_id_int)5894 void MessagesManager::on_pending_message_views_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int) {
5895   if (G()->close_flag()) {
5896     return;
5897   }
5898 
5899   auto messages_manager = static_cast<MessagesManager *>(messages_manager_ptr);
5900   send_closure_later(messages_manager->actor_id(messages_manager), &MessagesManager::on_pending_message_views_timeout,
5901                      DialogId(dialog_id_int));
5902 }
5903 
on_pending_message_live_location_view_timeout_callback(void * messages_manager_ptr,int64 task_id)5904 void MessagesManager::on_pending_message_live_location_view_timeout_callback(void *messages_manager_ptr,
5905                                                                              int64 task_id) {
5906   if (G()->close_flag()) {
5907     return;
5908   }
5909 
5910   auto messages_manager = static_cast<MessagesManager *>(messages_manager_ptr);
5911   send_closure_later(messages_manager->actor_id(messages_manager),
5912                      &MessagesManager::view_message_live_location_on_server, task_id);
5913 }
5914 
on_pending_draft_message_timeout_callback(void * messages_manager_ptr,int64 dialog_id_int)5915 void MessagesManager::on_pending_draft_message_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int) {
5916   if (G()->close_flag()) {
5917     return;
5918   }
5919 
5920   auto messages_manager = static_cast<MessagesManager *>(messages_manager_ptr);
5921   send_closure_later(messages_manager->actor_id(messages_manager),
5922                      &MessagesManager::save_dialog_draft_message_on_server, DialogId(dialog_id_int));
5923 }
5924 
on_pending_read_history_timeout_callback(void * messages_manager_ptr,int64 dialog_id_int)5925 void MessagesManager::on_pending_read_history_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int) {
5926   if (G()->close_flag()) {
5927     return;
5928   }
5929 
5930   auto messages_manager = static_cast<MessagesManager *>(messages_manager_ptr);
5931   send_closure_later(messages_manager->actor_id(messages_manager), &MessagesManager::do_read_history_on_server,
5932                      DialogId(dialog_id_int));
5933 }
5934 
on_pending_updated_dialog_timeout_callback(void * messages_manager_ptr,int64 dialog_id_int)5935 void MessagesManager::on_pending_updated_dialog_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int) {
5936   // no check for G()->close_flag() to save dialogs even while closing
5937 
5938   auto messages_manager = static_cast<MessagesManager *>(messages_manager_ptr);
5939   // TODO it is unsafe to save dialog to database before binlog is flushed
5940 
5941   // no send_closure_later, because messages_manager can be not an actor while closing
5942   messages_manager->save_dialog_to_database(DialogId(dialog_id_int));
5943 }
5944 
on_pending_unload_dialog_timeout_callback(void * messages_manager_ptr,int64 dialog_id_int)5945 void MessagesManager::on_pending_unload_dialog_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int) {
5946   if (G()->close_flag()) {
5947     return;
5948   }
5949 
5950   auto messages_manager = static_cast<MessagesManager *>(messages_manager_ptr);
5951   send_closure_later(messages_manager->actor_id(messages_manager), &MessagesManager::unload_dialog,
5952                      DialogId(dialog_id_int));
5953 }
5954 
on_dialog_unmute_timeout_callback(void * messages_manager_ptr,int64 dialog_id_int)5955 void MessagesManager::on_dialog_unmute_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int) {
5956   if (G()->close_flag()) {
5957     return;
5958   }
5959 
5960   auto messages_manager = static_cast<MessagesManager *>(messages_manager_ptr);
5961   if (1 <= dialog_id_int && dialog_id_int <= 3) {
5962     send_closure_later(messages_manager->actor_id(messages_manager), &MessagesManager::on_scope_unmute,
5963                        static_cast<NotificationSettingsScope>(dialog_id_int - 1));
5964   } else {
5965     send_closure_later(messages_manager->actor_id(messages_manager), &MessagesManager::on_dialog_unmute,
5966                        DialogId(dialog_id_int));
5967   }
5968 }
5969 
on_pending_send_dialog_action_timeout_callback(void * messages_manager_ptr,int64 dialog_id_int)5970 void MessagesManager::on_pending_send_dialog_action_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int) {
5971   if (G()->close_flag()) {
5972     return;
5973   }
5974 
5975   auto messages_manager = static_cast<MessagesManager *>(messages_manager_ptr);
5976   send_closure_later(messages_manager->actor_id(messages_manager), &MessagesManager::on_send_dialog_action_timeout,
5977                      DialogId(dialog_id_int));
5978 }
5979 
on_active_dialog_action_timeout_callback(void * messages_manager_ptr,int64 dialog_id_int)5980 void MessagesManager::on_active_dialog_action_timeout_callback(void *messages_manager_ptr, int64 dialog_id_int) {
5981   if (G()->close_flag()) {
5982     return;
5983   }
5984 
5985   auto messages_manager = static_cast<MessagesManager *>(messages_manager_ptr);
5986   send_closure_later(messages_manager->actor_id(messages_manager), &MessagesManager::on_active_dialog_action_timeout,
5987                      DialogId(dialog_id_int));
5988 }
5989 
on_update_dialog_online_member_count_timeout_callback(void * messages_manager_ptr,int64 dialog_id_int)5990 void MessagesManager::on_update_dialog_online_member_count_timeout_callback(void *messages_manager_ptr,
5991                                                                             int64 dialog_id_int) {
5992   if (G()->close_flag()) {
5993     return;
5994   }
5995 
5996   auto messages_manager = static_cast<MessagesManager *>(messages_manager_ptr);
5997   send_closure_later(messages_manager->actor_id(messages_manager),
5998                      &MessagesManager::on_update_dialog_online_member_count_timeout, DialogId(dialog_id_int));
5999 }
6000 
on_preload_folder_dialog_list_timeout_callback(void * messages_manager_ptr,int64 folder_id_int)6001 void MessagesManager::on_preload_folder_dialog_list_timeout_callback(void *messages_manager_ptr, int64 folder_id_int) {
6002   if (G()->close_flag()) {
6003     return;
6004   }
6005 
6006   auto messages_manager = static_cast<MessagesManager *>(messages_manager_ptr);
6007   send_closure_later(messages_manager->actor_id(messages_manager), &MessagesManager::preload_folder_dialog_list,
6008                      FolderId(narrow_cast<int32>(folder_id_int)));
6009 }
6010 
get_dialog_database_value(const Dialog * d)6011 BufferSlice MessagesManager::get_dialog_database_value(const Dialog *d) {
6012   // can't use log_event_store, because it tries to parse stored Dialog
6013   LogEventStorerCalcLength storer_calc_length;
6014   store(*d, storer_calc_length);
6015 
6016   BufferSlice value_buffer{storer_calc_length.get_length()};
6017   auto value = value_buffer.as_slice();
6018 
6019   LogEventStorerUnsafe storer_unsafe(value.ubegin());
6020   store(*d, storer_unsafe);
6021   return value_buffer;
6022 }
6023 
save_dialog_to_database(DialogId dialog_id)6024 void MessagesManager::save_dialog_to_database(DialogId dialog_id) {
6025   CHECK(G()->parameters().use_message_db);
6026   auto d = get_dialog(dialog_id);
6027   CHECK(d != nullptr);
6028   LOG(INFO) << "Save " << dialog_id << " to database";
6029   vector<NotificationGroupKey> changed_group_keys;
6030   bool can_reuse_notification_group = false;
6031   auto add_group_key = [&](auto &group_info) {
6032     if (group_info.is_changed) {
6033       can_reuse_notification_group |= group_info.try_reuse;
6034       changed_group_keys.emplace_back(group_info.group_id, group_info.try_reuse ? DialogId() : dialog_id,
6035                                       group_info.last_notification_date);
6036       group_info.is_changed = false;
6037     }
6038   };
6039   add_group_key(d->message_notification_group);
6040   add_group_key(d->mention_notification_group);
6041   auto fixed_folder_id = d->folder_id == FolderId::archive() ? FolderId::archive() : FolderId::main();
6042   G()->td_db()->get_dialog_db_async()->add_dialog(
6043       dialog_id, fixed_folder_id, d->is_folder_id_inited ? d->order : 0, get_dialog_database_value(d),
6044       std::move(changed_group_keys), PromiseCreator::lambda([dialog_id, can_reuse_notification_group](Result<> result) {
6045         send_closure(G()->messages_manager(), &MessagesManager::on_save_dialog_to_database, dialog_id,
6046                      can_reuse_notification_group, result.is_ok());
6047       }));
6048 }
6049 
on_save_dialog_to_database(DialogId dialog_id,bool can_reuse_notification_group,bool success)6050 void MessagesManager::on_save_dialog_to_database(DialogId dialog_id, bool can_reuse_notification_group, bool success) {
6051   LOG(INFO) << "Successfully saved " << dialog_id << " to database";
6052 
6053   if (success && can_reuse_notification_group && !G()->close_flag()) {
6054     auto d = get_dialog(dialog_id);
6055     CHECK(d != nullptr);
6056     try_reuse_notification_group(d->message_notification_group);
6057     try_reuse_notification_group(d->mention_notification_group);
6058   }
6059 
6060   // TODO erase some events from binlog
6061 }
6062 
try_reuse_notification_group(NotificationGroupInfo & group_info)6063 void MessagesManager::try_reuse_notification_group(NotificationGroupInfo &group_info) {
6064   if (!group_info.try_reuse) {
6065     return;
6066   }
6067   if (group_info.is_changed) {
6068     LOG(ERROR) << "Failed to reuse changed " << group_info.group_id;
6069     return;
6070   }
6071   group_info.try_reuse = false;
6072   if (!group_info.group_id.is_valid()) {
6073     LOG(ERROR) << "Failed to reuse invalid " << group_info.group_id;
6074     return;
6075   }
6076   CHECK(group_info.last_notification_id == NotificationId());
6077   CHECK(group_info.last_notification_date == 0);
6078   send_closure_later(G()->notification_manager(), &NotificationManager::try_reuse_notification_group_id,
6079                      group_info.group_id);
6080   notification_group_id_to_dialog_id_.erase(group_info.group_id);
6081   group_info.group_id = NotificationGroupId();
6082   group_info.max_removed_notification_id = NotificationId();
6083   group_info.max_removed_message_id = MessageId();
6084 }
6085 
invalidate_message_indexes(Dialog * d)6086 void MessagesManager::invalidate_message_indexes(Dialog *d) {
6087   CHECK(d != nullptr);
6088   bool is_secret = d->dialog_id.get_type() == DialogType::SecretChat;
6089   for (size_t i = 0; i < d->message_count_by_index.size(); i++) {
6090     if (is_secret || i == static_cast<size_t>(message_search_filter_index(MessageSearchFilter::FailedToSend))) {
6091       // always know all messages
6092       d->first_database_message_id_by_index[i] = MessageId::min();
6093       // keep the count
6094     } else {
6095       // some messages are unknown; drop first_database_message_id and count
6096       d->first_database_message_id_by_index[i] = MessageId();
6097       d->message_count_by_index[i] = -1;
6098     }
6099   }
6100 }
6101 
update_message_count_by_index(Dialog * d,int diff,const Message * m)6102 void MessagesManager::update_message_count_by_index(Dialog *d, int diff, const Message *m) {
6103   auto index_mask = get_message_index_mask(d->dialog_id, m);
6104   index_mask &= ~message_search_filter_index_mask(
6105       MessageSearchFilter::UnreadMention);  // unread mention count has been already manually updated
6106 
6107   update_message_count_by_index(d, diff, index_mask);
6108 }
6109 
update_message_count_by_index(Dialog * d,int diff,int32 index_mask)6110 void MessagesManager::update_message_count_by_index(Dialog *d, int diff, int32 index_mask) {
6111   if (index_mask == 0) {
6112     return;
6113   }
6114 
6115   LOG(INFO) << "Update message count by " << diff << " in index mask " << index_mask;
6116   int i = 0;
6117   for (auto &message_count : d->message_count_by_index) {
6118     if (((index_mask >> i) & 1) != 0 && message_count != -1) {
6119       message_count += diff;
6120       if (message_count < 0) {
6121         if (d->dialog_id.get_type() == DialogType::SecretChat ||
6122             i == message_search_filter_index(MessageSearchFilter::FailedToSend)) {
6123           message_count = 0;
6124         } else {
6125           message_count = -1;
6126         }
6127       }
6128       on_dialog_updated(d->dialog_id, "update_message_count_by_index");
6129     }
6130     i++;
6131   }
6132 
6133   i = static_cast<int>(MessageSearchFilter::Call) - 1;
6134   for (auto &message_count : calls_db_state_.message_count_by_index) {
6135     if (((index_mask >> i) & 1) != 0 && message_count != -1) {
6136       message_count += diff;
6137       if (message_count < 0) {
6138         if (d->dialog_id.get_type() == DialogType::SecretChat) {
6139           message_count = 0;
6140         } else {
6141           message_count = -1;
6142         }
6143       }
6144       save_calls_db_state();
6145     }
6146     i++;
6147   }
6148 }
6149 
get_message_index_mask(DialogId dialog_id,const Message * m) const6150 int32 MessagesManager::get_message_index_mask(DialogId dialog_id, const Message *m) const {
6151   CHECK(m != nullptr);
6152   if (m->message_id.is_scheduled() || m->message_id.is_yet_unsent()) {
6153     return 0;
6154   }
6155   if (m->is_failed_to_send) {
6156     return message_search_filter_index_mask(MessageSearchFilter::FailedToSend);
6157   }
6158   bool is_secret = dialog_id.get_type() == DialogType::SecretChat;
6159   if (!m->message_id.is_server() && !is_secret) {
6160     return 0;
6161   }
6162 
6163   int32 index_mask = 0;
6164   if (m->is_pinned) {
6165     index_mask |= message_search_filter_index_mask(MessageSearchFilter::Pinned);
6166   }
6167   // retain second condition just in case
6168   if (m->is_content_secret || (m->ttl > 0 && !is_secret)) {
6169     return index_mask;
6170   }
6171   index_mask |= get_message_content_index_mask(m->content.get(), td_, m->is_outgoing);
6172   if (m->contains_mention) {
6173     index_mask |= message_search_filter_index_mask(MessageSearchFilter::Mention);
6174     if (m->contains_unread_mention) {
6175       index_mask |= message_search_filter_index_mask(MessageSearchFilter::UnreadMention);
6176     }
6177   }
6178   LOG(INFO) << "Have index mask " << index_mask << " for " << m->message_id << " in " << dialog_id;
6179   return index_mask;
6180 }
6181 
update_reply_count_by_message(Dialog * d,int diff,const Message * m)6182 void MessagesManager::update_reply_count_by_message(Dialog *d, int diff, const Message *m) {
6183   CHECK(d != nullptr);
6184   CHECK(m != nullptr);
6185   if (td_->auth_manager_->is_bot() || !m->top_thread_message_id.is_valid() ||
6186       m->top_thread_message_id == m->message_id || !m->message_id.is_valid() || !m->message_id.is_server()) {
6187     return;
6188   }
6189 
6190   update_message_reply_count(d, m->top_thread_message_id, get_message_sender(m), m->message_id,
6191                              diff < 0 ? G()->unix_time() : m->date, diff);
6192 }
6193 
update_message_reply_count(Dialog * d,MessageId message_id,DialogId replier_dialog_id,MessageId reply_message_id,int32 update_date,int diff,bool is_recursive)6194 void MessagesManager::update_message_reply_count(Dialog *d, MessageId message_id, DialogId replier_dialog_id,
6195                                                  MessageId reply_message_id, int32 update_date, int diff,
6196                                                  bool is_recursive) {
6197   if (d == nullptr) {
6198     return;
6199   }
6200 
6201   Message *m = get_message(d, message_id);
6202   if (m == nullptr || !is_active_message_reply_info(d->dialog_id, m->reply_info)) {
6203     return;
6204   }
6205   LOG(INFO) << "Update reply count to " << message_id << " in " << d->dialog_id << " by " << diff << " from "
6206             << reply_message_id << " sent by " << replier_dialog_id;
6207   if (m->interaction_info_update_date < update_date &&
6208       m->reply_info.add_reply(replier_dialog_id, reply_message_id, diff)) {
6209     on_message_reply_info_changed(d->dialog_id, m);
6210     on_message_changed(d, m, true, "update_message_reply_count_by_message");
6211   }
6212 
6213   if (!is_recursive && is_discussion_message(d->dialog_id, m)) {
6214     update_message_reply_count(get_dialog(m->forward_info->from_dialog_id), m->forward_info->from_message_id,
6215                                replier_dialog_id, reply_message_id, update_date, diff, true);
6216   }
6217 }
6218 
get_message_ids(const vector<int64> & input_message_ids)6219 vector<MessageId> MessagesManager::get_message_ids(const vector<int64> &input_message_ids) {
6220   vector<MessageId> message_ids;
6221   message_ids.reserve(input_message_ids.size());
6222   for (auto &input_message_id : input_message_ids) {
6223     message_ids.push_back(MessageId(input_message_id));
6224   }
6225   return message_ids;
6226 }
6227 
get_server_message_ids(const vector<MessageId> & message_ids)6228 vector<int32> MessagesManager::get_server_message_ids(const vector<MessageId> &message_ids) {
6229   return transform(message_ids, [](MessageId message_id) { return message_id.get_server_message_id().get(); });
6230 }
6231 
get_scheduled_server_message_ids(const vector<MessageId> & message_ids)6232 vector<int32> MessagesManager::get_scheduled_server_message_ids(const vector<MessageId> &message_ids) {
6233   return transform(message_ids,
6234                    [](MessageId message_id) { return message_id.get_scheduled_server_message_id().get(); });
6235 }
6236 
get_input_peer(DialogId dialog_id,AccessRights access_rights) const6237 tl_object_ptr<telegram_api::InputPeer> MessagesManager::get_input_peer(DialogId dialog_id,
6238                                                                        AccessRights access_rights) const {
6239   switch (dialog_id.get_type()) {
6240     case DialogType::User:
6241       return td_->contacts_manager_->get_input_peer_user(dialog_id.get_user_id(), access_rights);
6242     case DialogType::Chat:
6243       return td_->contacts_manager_->get_input_peer_chat(dialog_id.get_chat_id(), access_rights);
6244     case DialogType::Channel:
6245       return td_->contacts_manager_->get_input_peer_channel(dialog_id.get_channel_id(), access_rights);
6246     case DialogType::SecretChat:
6247       return nullptr;
6248     case DialogType::None:
6249       return make_tl_object<telegram_api::inputPeerEmpty>();
6250     default:
6251       UNREACHABLE();
6252       return nullptr;
6253   }
6254 }
6255 
get_input_peer_force(DialogId dialog_id)6256 tl_object_ptr<telegram_api::InputPeer> MessagesManager::get_input_peer_force(DialogId dialog_id) {
6257   switch (dialog_id.get_type()) {
6258     case DialogType::User: {
6259       UserId user_id = dialog_id.get_user_id();
6260       return make_tl_object<telegram_api::inputPeerUser>(user_id.get(), 0);
6261     }
6262     case DialogType::Chat: {
6263       ChatId chat_id = dialog_id.get_chat_id();
6264       return make_tl_object<telegram_api::inputPeerChat>(chat_id.get());
6265     }
6266     case DialogType::Channel: {
6267       ChannelId channel_id = dialog_id.get_channel_id();
6268       return make_tl_object<telegram_api::inputPeerChannel>(channel_id.get(), 0);
6269     }
6270     case DialogType::SecretChat:
6271     case DialogType::None:
6272       return make_tl_object<telegram_api::inputPeerEmpty>();
6273     default:
6274       UNREACHABLE();
6275       return nullptr;
6276   }
6277 }
6278 
get_input_peers(const vector<DialogId> & dialog_ids,AccessRights access_rights) const6279 vector<tl_object_ptr<telegram_api::InputPeer>> MessagesManager::get_input_peers(const vector<DialogId> &dialog_ids,
6280                                                                                 AccessRights access_rights) const {
6281   vector<tl_object_ptr<telegram_api::InputPeer>> input_peers;
6282   input_peers.reserve(dialog_ids.size());
6283   for (auto &dialog_id : dialog_ids) {
6284     auto input_peer = get_input_peer(dialog_id, access_rights);
6285     if (input_peer == nullptr) {
6286       LOG(ERROR) << "Have no access to " << dialog_id;
6287       continue;
6288     }
6289     input_peers.push_back(std::move(input_peer));
6290   }
6291   return input_peers;
6292 }
6293 
get_input_dialog_peer(DialogId dialog_id,AccessRights access_rights) const6294 tl_object_ptr<telegram_api::InputDialogPeer> MessagesManager::get_input_dialog_peer(DialogId dialog_id,
6295                                                                                     AccessRights access_rights) const {
6296   switch (dialog_id.get_type()) {
6297     case DialogType::User:
6298     case DialogType::Chat:
6299     case DialogType::Channel:
6300     case DialogType::None:
6301       return make_tl_object<telegram_api::inputDialogPeer>(get_input_peer(dialog_id, access_rights));
6302     case DialogType::SecretChat:
6303       return nullptr;
6304     default:
6305       UNREACHABLE();
6306       return nullptr;
6307   }
6308 }
6309 
get_input_dialog_peers(const vector<DialogId> & dialog_ids,AccessRights access_rights) const6310 vector<tl_object_ptr<telegram_api::InputDialogPeer>> MessagesManager::get_input_dialog_peers(
6311     const vector<DialogId> &dialog_ids, AccessRights access_rights) const {
6312   vector<tl_object_ptr<telegram_api::InputDialogPeer>> input_dialog_peers;
6313   input_dialog_peers.reserve(dialog_ids.size());
6314   for (auto &dialog_id : dialog_ids) {
6315     auto input_dialog_peer = get_input_dialog_peer(dialog_id, access_rights);
6316     if (input_dialog_peer == nullptr) {
6317       LOG(ERROR) << "Have no access to " << dialog_id;
6318       continue;
6319     }
6320     input_dialog_peers.push_back(std::move(input_dialog_peer));
6321   }
6322   return input_dialog_peers;
6323 }
6324 
have_input_peer(DialogId dialog_id,AccessRights access_rights) const6325 bool MessagesManager::have_input_peer(DialogId dialog_id, AccessRights access_rights) const {
6326   switch (dialog_id.get_type()) {
6327     case DialogType::User: {
6328       UserId user_id = dialog_id.get_user_id();
6329       return td_->contacts_manager_->have_input_peer_user(user_id, access_rights);
6330     }
6331     case DialogType::Chat: {
6332       ChatId chat_id = dialog_id.get_chat_id();
6333       return td_->contacts_manager_->have_input_peer_chat(chat_id, access_rights);
6334     }
6335     case DialogType::Channel: {
6336       ChannelId channel_id = dialog_id.get_channel_id();
6337       return td_->contacts_manager_->have_input_peer_channel(channel_id, access_rights);
6338     }
6339     case DialogType::SecretChat: {
6340       SecretChatId secret_chat_id = dialog_id.get_secret_chat_id();
6341       return td_->contacts_manager_->have_input_encrypted_peer(secret_chat_id, access_rights);
6342     }
6343     case DialogType::None:
6344       return false;
6345     default:
6346       UNREACHABLE();
6347       return false;
6348   }
6349 }
6350 
have_dialog_info(DialogId dialog_id) const6351 bool MessagesManager::have_dialog_info(DialogId dialog_id) const {
6352   switch (dialog_id.get_type()) {
6353     case DialogType::User: {
6354       UserId user_id = dialog_id.get_user_id();
6355       return td_->contacts_manager_->have_user(user_id);
6356     }
6357     case DialogType::Chat: {
6358       ChatId chat_id = dialog_id.get_chat_id();
6359       return td_->contacts_manager_->have_chat(chat_id);
6360     }
6361     case DialogType::Channel: {
6362       ChannelId channel_id = dialog_id.get_channel_id();
6363       return td_->contacts_manager_->have_channel(channel_id);
6364     }
6365     case DialogType::SecretChat: {
6366       SecretChatId secret_chat_id = dialog_id.get_secret_chat_id();
6367       return td_->contacts_manager_->have_secret_chat(secret_chat_id);
6368     }
6369     case DialogType::None:
6370     default:
6371       return false;
6372   }
6373 }
6374 
have_dialog_info_force(DialogId dialog_id) const6375 bool MessagesManager::have_dialog_info_force(DialogId dialog_id) const {
6376   switch (dialog_id.get_type()) {
6377     case DialogType::User: {
6378       UserId user_id = dialog_id.get_user_id();
6379       return td_->contacts_manager_->have_user_force(user_id);
6380     }
6381     case DialogType::Chat: {
6382       ChatId chat_id = dialog_id.get_chat_id();
6383       return td_->contacts_manager_->have_chat_force(chat_id);
6384     }
6385     case DialogType::Channel: {
6386       ChannelId channel_id = dialog_id.get_channel_id();
6387       return td_->contacts_manager_->have_channel_force(channel_id);
6388     }
6389     case DialogType::SecretChat: {
6390       SecretChatId secret_chat_id = dialog_id.get_secret_chat_id();
6391       return td_->contacts_manager_->have_secret_chat_force(secret_chat_id);
6392     }
6393     case DialogType::None:
6394     default:
6395       return false;
6396   }
6397 }
6398 
get_input_encrypted_chat(DialogId dialog_id,AccessRights access_rights) const6399 tl_object_ptr<telegram_api::inputEncryptedChat> MessagesManager::get_input_encrypted_chat(
6400     DialogId dialog_id, AccessRights access_rights) const {
6401   switch (dialog_id.get_type()) {
6402     case DialogType::SecretChat: {
6403       SecretChatId secret_chat_id = dialog_id.get_secret_chat_id();
6404       return td_->contacts_manager_->get_input_encrypted_chat(secret_chat_id, access_rights);
6405     }
6406     case DialogType::User:
6407     case DialogType::Chat:
6408     case DialogType::Channel:
6409     case DialogType::None:
6410     default:
6411       UNREACHABLE();
6412       return nullptr;
6413   }
6414 }
6415 
is_allowed_useless_update(const tl_object_ptr<telegram_api::Update> & update)6416 bool MessagesManager::is_allowed_useless_update(const tl_object_ptr<telegram_api::Update> &update) {
6417   auto constructor_id = update->get_id();
6418   if (constructor_id == dummyUpdate::ID) {
6419     // allow dummyUpdate just in case
6420     return true;
6421   }
6422   if (constructor_id == telegram_api::updateNewMessage::ID ||
6423       constructor_id == telegram_api::updateNewChannelMessage::ID) {
6424     // new outgoing messages are received again if random_id coincide
6425     return true;
6426   }
6427 
6428   return false;
6429 }
6430 
skip_old_pending_pts_update(tl_object_ptr<telegram_api::Update> && update,int32 new_pts,int32 old_pts,int32 pts_count,const char * source)6431 void MessagesManager::skip_old_pending_pts_update(tl_object_ptr<telegram_api::Update> &&update, int32 new_pts,
6432                                                   int32 old_pts, int32 pts_count, const char *source) {
6433   if (update->get_id() == telegram_api::updateNewMessage::ID) {
6434     auto update_new_message = static_cast<telegram_api::updateNewMessage *>(update.get());
6435     auto full_message_id = get_full_message_id(update_new_message->message_, false);
6436     if (update_message_ids_.find(full_message_id) != update_message_ids_.end()) {
6437       if (new_pts == old_pts) {  // otherwise message can be already deleted
6438         // apply sent message anyway
6439         on_get_message(std::move(update_new_message->message_), true, false, false, true, true,
6440                        "updateNewMessage with an awaited message");
6441         return;
6442       } else {
6443         LOG(ERROR) << "Receive awaited sent " << full_message_id << " from " << source << " with pts " << new_pts
6444                    << " and pts_count " << pts_count << ", but current pts is " << old_pts;
6445         dump_debug_message_op(get_dialog(full_message_id.get_dialog_id()), 3);
6446       }
6447     }
6448   }
6449   if (update->get_id() == updateSentMessage::ID) {
6450     auto update_sent_message = static_cast<updateSentMessage *>(update.get());
6451     if (being_sent_messages_.count(update_sent_message->random_id_) > 0) {
6452       if (new_pts == old_pts) {  // otherwise message can be already deleted
6453         // apply sent message anyway
6454         on_send_message_success(update_sent_message->random_id_, update_sent_message->message_id_,
6455                                 update_sent_message->date_, update_sent_message->ttl_period_, FileId(),
6456                                 "process old updateSentMessage");
6457         return;
6458       } else {
6459         LOG(ERROR) << "Receive awaited sent " << update_sent_message->message_id_ << " from " << source << " with pts "
6460                    << new_pts << " and pts_count " << pts_count << ", but current pts is " << old_pts;
6461         dump_debug_message_op(get_dialog(being_sent_messages_[update_sent_message->random_id_].get_dialog_id()), 3);
6462       }
6463     }
6464     return;
6465   }
6466 
6467   // very old or unuseful update
6468   LOG_IF(WARNING, new_pts == old_pts && pts_count == 0 && !is_allowed_useless_update(update))
6469       << "Receive useless update " << oneline(to_string(update)) << " from " << source;
6470 }
6471 
get_service_notifications_dialog()6472 MessagesManager::Dialog *MessagesManager::get_service_notifications_dialog() {
6473   UserId service_notifications_user_id = td_->contacts_manager_->add_service_notifications_user();
6474   DialogId service_notifications_dialog_id(service_notifications_user_id);
6475   force_create_dialog(service_notifications_dialog_id, "get_service_notifications_dialog");
6476   return get_dialog(service_notifications_dialog_id);
6477 }
6478 
save_auth_notification_ids()6479 void MessagesManager::save_auth_notification_ids() {
6480   auto min_date = G()->unix_time() - AUTH_NOTIFICATION_ID_CACHE_TIME;
6481   vector<string> ids;
6482   for (auto &it : auth_notification_id_date_) {
6483     auto date = it.second;
6484     if (date < min_date) {
6485       continue;
6486     }
6487     ids.push_back(it.first);
6488     ids.push_back(to_string(date));
6489   }
6490 
6491   if (ids.empty()) {
6492     G()->td_db()->get_binlog_pmc()->erase("auth_notification_ids");
6493     return;
6494   }
6495 
6496   G()->td_db()->get_binlog_pmc()->set("auth_notification_ids", implode(ids, ','));
6497 }
6498 
on_update_service_notification(tl_object_ptr<telegram_api::updateServiceNotification> && update,bool skip_new_entities,Promise<Unit> && promise)6499 void MessagesManager::on_update_service_notification(tl_object_ptr<telegram_api::updateServiceNotification> &&update,
6500                                                      bool skip_new_entities, Promise<Unit> &&promise) {
6501   bool has_date = (update->flags_ & telegram_api::updateServiceNotification::INBOX_DATE_MASK) != 0;
6502   auto date = has_date ? update->inbox_date_ : G()->unix_time();
6503   if (date <= 0) {
6504     LOG(ERROR) << "Receive message date " << date << " in " << to_string(update);
6505     return;
6506   }
6507   bool is_auth_notification = begins_with(update->type_, "auth");
6508   if (is_auth_notification) {
6509     auto &old_date = auth_notification_id_date_[update->type_.substr(4)];
6510     if (date <= old_date) {
6511       LOG(INFO) << "Skip already applied " << to_string(update);
6512       return;
6513     }
6514     old_date = date;
6515   }
6516 
6517   bool is_authorized = td_->auth_manager_->is_authorized();
6518   bool is_user = is_authorized && !td_->auth_manager_->is_bot();
6519   auto contacts_manager = is_authorized ? td_->contacts_manager_.get() : nullptr;
6520   auto message_text = get_message_text(contacts_manager, std::move(update->message_), std::move(update->entities_),
6521                                        skip_new_entities, !is_user, date, false, "on_update_service_notification");
6522   DialogId owner_dialog_id = is_user ? get_service_notifications_dialog()->dialog_id : DialogId();
6523   int32 ttl = 0;
6524   bool disable_web_page_preview = false;
6525   auto content = get_message_content(td_, std::move(message_text), std::move(update->media_), owner_dialog_id, false,
6526                                      UserId(), &ttl, &disable_web_page_preview);
6527   bool is_content_secret = is_secret_message_content(ttl, content->get_type());
6528 
6529   if (update->popup_) {
6530     send_closure(G()->td(), &Td::send_update,
6531                  td_api::make_object<td_api::updateServiceNotification>(
6532                      update->type_, get_message_content_object(content.get(), td_, owner_dialog_id, date,
6533                                                                is_content_secret, true, -1)));
6534   }
6535   if (has_date && is_user) {
6536     Dialog *d = get_service_notifications_dialog();
6537     CHECK(d != nullptr);
6538     auto dialog_id = d->dialog_id;
6539     CHECK(dialog_id.get_type() == DialogType::User);
6540 
6541     auto new_message = make_unique<Message>();
6542     set_message_id(new_message, get_next_local_message_id(d));
6543     new_message->sender_user_id = dialog_id.get_user_id();
6544     new_message->date = date;
6545     new_message->ttl = ttl;
6546     new_message->disable_web_page_preview = disable_web_page_preview;
6547     new_message->is_content_secret = is_content_secret;
6548     new_message->content = std::move(content);
6549     new_message->have_previous = true;
6550     new_message->have_next = true;
6551 
6552     bool need_update = true;
6553     bool need_update_dialog_pos = false;
6554 
6555     const Message *m = add_message_to_dialog(d, std::move(new_message), true, &need_update, &need_update_dialog_pos,
6556                                              "on_update_service_notification");
6557     if (m != nullptr && need_update) {
6558       send_update_new_message(d, m);
6559     }
6560     register_new_local_message_id(d, m);
6561 
6562     if (need_update_dialog_pos) {
6563       send_update_chat_last_message(d, "on_update_service_notification");
6564     }
6565   }
6566   promise.set_value(Unit());
6567 
6568   if (is_auth_notification) {
6569     save_auth_notification_ids();
6570   }
6571 }
6572 
on_update_read_channel_inbox(tl_object_ptr<telegram_api::updateReadChannelInbox> && update)6573 void MessagesManager::on_update_read_channel_inbox(tl_object_ptr<telegram_api::updateReadChannelInbox> &&update) {
6574   ChannelId channel_id(update->channel_id_);
6575   if (!channel_id.is_valid()) {
6576     LOG(ERROR) << "Receive invalid " << channel_id << " in updateReadChannelInbox";
6577     return;
6578   }
6579 
6580   FolderId folder_id;
6581   if ((update->flags_ & telegram_api::updateReadChannelInbox::FOLDER_ID_MASK) != 0) {
6582     folder_id = FolderId(update->folder_id_);
6583   }
6584   on_update_dialog_folder_id(DialogId(channel_id), folder_id);
6585   on_read_channel_inbox(channel_id, MessageId(ServerMessageId(update->max_id_)), update->still_unread_count_,
6586                         update->pts_, "updateReadChannelInbox");
6587 }
6588 
on_update_read_channel_outbox(tl_object_ptr<telegram_api::updateReadChannelOutbox> && update)6589 void MessagesManager::on_update_read_channel_outbox(tl_object_ptr<telegram_api::updateReadChannelOutbox> &&update) {
6590   ChannelId channel_id(update->channel_id_);
6591   if (!channel_id.is_valid()) {
6592     LOG(ERROR) << "Receive invalid " << channel_id << " in updateReadChannelOutbox";
6593     return;
6594   }
6595 
6596   DialogId dialog_id = DialogId(channel_id);
6597   read_history_outbox(dialog_id, MessageId(ServerMessageId(update->max_id_)));
6598 }
6599 
on_update_read_channel_messages_contents(tl_object_ptr<telegram_api::updateChannelReadMessagesContents> && update)6600 void MessagesManager::on_update_read_channel_messages_contents(
6601     tl_object_ptr<telegram_api::updateChannelReadMessagesContents> &&update) {
6602   ChannelId channel_id(update->channel_id_);
6603   if (!channel_id.is_valid()) {
6604     LOG(ERROR) << "Receive invalid " << channel_id << " in updateChannelReadMessagesContents";
6605     return;
6606   }
6607 
6608   DialogId dialog_id = DialogId(channel_id);
6609 
6610   Dialog *d = get_dialog_force(dialog_id, "on_update_read_channel_messages_contents");
6611   if (d == nullptr) {
6612     LOG(INFO) << "Receive read channel messages contents update in unknown " << dialog_id;
6613     return;
6614   }
6615 
6616   for (auto &server_message_id : update->messages_) {
6617     read_channel_message_content_from_updates(d, MessageId(ServerMessageId(server_message_id)));
6618   }
6619 }
6620 
on_update_read_message_comments(DialogId dialog_id,MessageId message_id,MessageId max_message_id,MessageId last_read_inbox_message_id,MessageId last_read_outbox_message_id)6621 void MessagesManager::on_update_read_message_comments(DialogId dialog_id, MessageId message_id,
6622                                                       MessageId max_message_id, MessageId last_read_inbox_message_id,
6623                                                       MessageId last_read_outbox_message_id) {
6624   Dialog *d = get_dialog_force(dialog_id, "on_update_read_message_comments");
6625   if (d == nullptr) {
6626     LOG(INFO) << "Ignore update of read message comments in unknown " << dialog_id << " in updateReadDiscussion";
6627     return;
6628   }
6629 
6630   auto m = get_message_force(d, message_id, "on_update_read_message_comments");
6631   if (m == nullptr || !m->message_id.is_server() || m->top_thread_message_id != m->message_id ||
6632       !is_active_message_reply_info(dialog_id, m->reply_info)) {
6633     return;
6634   }
6635   if (m->reply_info.update_max_message_ids(max_message_id, last_read_inbox_message_id, last_read_outbox_message_id)) {
6636     on_message_reply_info_changed(dialog_id, m);
6637     on_message_changed(d, m, true, "on_update_read_message_comments");
6638   }
6639 }
6640 
on_update_channel_too_long(tl_object_ptr<telegram_api::updateChannelTooLong> && update,bool force_apply)6641 void MessagesManager::on_update_channel_too_long(tl_object_ptr<telegram_api::updateChannelTooLong> &&update,
6642                                                  bool force_apply) {
6643   ChannelId channel_id(update->channel_id_);
6644   if (!channel_id.is_valid()) {
6645     LOG(ERROR) << "Receive invalid " << channel_id << " in updateChannelTooLong";
6646     return;
6647   }
6648 
6649   DialogId dialog_id = DialogId(channel_id);
6650   auto d = get_dialog_force(dialog_id, "on_update_channel_too_long 4");
6651   if (d == nullptr) {
6652     auto pts = load_channel_pts(dialog_id);
6653     if (pts > 0) {
6654       d = add_dialog(dialog_id, "on_update_channel_too_long 5");
6655       CHECK(d != nullptr);
6656       CHECK(d->pts == pts);
6657       update_dialog_pos(d, "on_update_channel_too_long 6");
6658     }
6659   }
6660 
6661   int32 update_pts = (update->flags_ & UPDATE_CHANNEL_TO_LONG_FLAG_HAS_PTS) ? update->pts_ : 0;
6662 
6663   if (d != nullptr) {
6664     if (update_pts == 0 || update_pts > d->pts) {
6665       get_channel_difference(dialog_id, d->pts, true, "on_update_channel_too_long 1");
6666     }
6667   } else {
6668     if (force_apply) {
6669       get_channel_difference(dialog_id, -1, true, "on_update_channel_too_long 2");
6670     } else {
6671       td_->updates_manager_->schedule_get_difference("on_update_channel_too_long 3");
6672     }
6673   }
6674 }
6675 
on_update_message_view_count(FullMessageId full_message_id,int32 view_count)6676 void MessagesManager::on_update_message_view_count(FullMessageId full_message_id, int32 view_count) {
6677   if (view_count < 0) {
6678     LOG(ERROR) << "Receive " << view_count << " views in updateChannelMessageViews for " << full_message_id;
6679     return;
6680   }
6681   update_message_interaction_info(full_message_id, view_count, -1, false, nullptr);
6682 }
6683 
on_update_message_forward_count(FullMessageId full_message_id,int32 forward_count)6684 void MessagesManager::on_update_message_forward_count(FullMessageId full_message_id, int32 forward_count) {
6685   if (forward_count < 0) {
6686     LOG(ERROR) << "Receive " << forward_count << " forwards in updateChannelMessageForwards for " << full_message_id;
6687     return;
6688   }
6689   update_message_interaction_info(full_message_id, -1, forward_count, false, nullptr);
6690 }
6691 
on_update_message_interaction_info(FullMessageId full_message_id,int32 view_count,int32 forward_count,bool has_reply_info,tl_object_ptr<telegram_api::messageReplies> && reply_info)6692 void MessagesManager::on_update_message_interaction_info(FullMessageId full_message_id, int32 view_count,
6693                                                          int32 forward_count, bool has_reply_info,
6694                                                          tl_object_ptr<telegram_api::messageReplies> &&reply_info) {
6695   if (view_count < 0 || forward_count < 0) {
6696     LOG(ERROR) << "Receive " << view_count << "/" << forward_count << " interaction counters for " << full_message_id;
6697     return;
6698   }
6699   update_message_interaction_info(full_message_id, view_count, forward_count, has_reply_info, std::move(reply_info));
6700 }
6701 
on_pending_message_views_timeout(DialogId dialog_id)6702 void MessagesManager::on_pending_message_views_timeout(DialogId dialog_id) {
6703   if (G()->close_flag()) {
6704     return;
6705   }
6706 
6707   auto d = get_dialog(dialog_id);
6708   CHECK(d != nullptr);
6709 
6710   const size_t MAX_MESSAGE_VIEWS = 100;  // server side limit
6711   vector<MessageId> message_ids;
6712   message_ids.reserve(min(d->pending_viewed_message_ids.size(), MAX_MESSAGE_VIEWS));
6713   for (auto message_id : d->pending_viewed_message_ids) {
6714     message_ids.push_back(message_id);
6715     if (message_ids.size() >= MAX_MESSAGE_VIEWS) {
6716       td_->create_handler<GetMessagesViewsQuery>()->send(dialog_id, std::move(message_ids), d->increment_view_counter);
6717       message_ids.clear();
6718     }
6719   }
6720   if (!message_ids.empty()) {
6721     td_->create_handler<GetMessagesViewsQuery>()->send(dialog_id, std::move(message_ids), d->increment_view_counter);
6722   }
6723   d->pending_viewed_message_ids.clear();
6724   d->increment_view_counter = false;
6725 }
6726 
update_message_interaction_info(FullMessageId full_message_id,int32 view_count,int32 forward_count,bool has_reply_info,tl_object_ptr<telegram_api::messageReplies> && reply_info)6727 void MessagesManager::update_message_interaction_info(FullMessageId full_message_id, int32 view_count,
6728                                                       int32 forward_count, bool has_reply_info,
6729                                                       tl_object_ptr<telegram_api::messageReplies> &&reply_info) {
6730   auto dialog_id = full_message_id.get_dialog_id();
6731   Dialog *d = get_dialog_force(dialog_id, "update_message_interaction_info");
6732   if (d == nullptr) {
6733     return;
6734   }
6735   auto message_id = full_message_id.get_message_id();
6736   Message *m = get_message_force(d, message_id, "update_message_interaction_info");
6737   if (m == nullptr) {
6738     LOG(INFO) << "Ignore message interaction info about unknown " << full_message_id;
6739     if (!message_id.is_scheduled() && message_id > d->last_new_message_id &&
6740         dialog_id.get_type() == DialogType::Channel) {
6741       get_channel_difference(dialog_id, d->pts, true, "update_message_interaction_info");
6742     }
6743     return;
6744   }
6745 
6746   if (view_count < 0) {
6747     view_count = m->view_count;
6748   }
6749   if (forward_count < 0) {
6750     forward_count = m->forward_count;
6751   }
6752   bool is_empty_reply_info = reply_info == nullptr;
6753   MessageReplyInfo new_reply_info(std::move(reply_info), td_->auth_manager_->is_bot());
6754   if (new_reply_info.is_empty() && !is_empty_reply_info) {
6755     has_reply_info = false;
6756   }
6757 
6758   if (update_message_interaction_info(dialog_id, m, view_count, forward_count, has_reply_info,
6759                                       std::move(new_reply_info), "update_message_interaction_info")) {
6760     on_message_changed(d, m, true, "update_message_interaction_info");
6761   }
6762 }
6763 
is_active_message_reply_info(DialogId dialog_id,const MessageReplyInfo & info) const6764 bool MessagesManager::is_active_message_reply_info(DialogId dialog_id, const MessageReplyInfo &info) const {
6765   if (info.is_empty()) {
6766     return false;
6767   }
6768   if (dialog_id.get_type() != DialogType::Channel) {
6769     return false;
6770   }
6771 
6772   if (!info.is_comment) {
6773     return true;
6774   }
6775   if (!is_broadcast_channel(dialog_id)) {
6776     return true;
6777   }
6778 
6779   auto channel_id = dialog_id.get_channel_id();
6780   if (!td_->contacts_manager_->get_channel_has_linked_channel(channel_id)) {
6781     return false;
6782   }
6783 
6784   auto linked_channel_id = td_->contacts_manager_->get_channel_linked_channel_id(channel_id);
6785   if (!linked_channel_id.is_valid()) {
6786     // keep the comment button while linked channel is unknown
6787     send_closure_later(G()->contacts_manager(), &ContactsManager::load_channel_full, channel_id, false, Promise<Unit>(),
6788                        "is_active_message_reply_info");
6789     return true;
6790   }
6791 
6792   return linked_channel_id == info.channel_id;
6793 }
6794 
is_visible_message_reply_info(DialogId dialog_id,const Message * m) const6795 bool MessagesManager::is_visible_message_reply_info(DialogId dialog_id, const Message *m) const {
6796   CHECK(m != nullptr);
6797   if (!m->message_id.is_valid()) {
6798     return false;
6799   }
6800   bool is_broadcast = is_broadcast_channel(dialog_id);
6801   if (!m->message_id.is_server() && !(is_broadcast && m->message_id.is_yet_unsent())) {
6802     return false;
6803   }
6804   if (is_broadcast && (m->had_reply_markup || m->reply_markup != nullptr)) {
6805     return false;
6806   }
6807   return is_active_message_reply_info(dialog_id, m->reply_info);
6808 }
6809 
on_message_reply_info_changed(DialogId dialog_id,const Message * m) const6810 void MessagesManager::on_message_reply_info_changed(DialogId dialog_id, const Message *m) const {
6811   if (td_->auth_manager_->is_bot()) {
6812     return;
6813   }
6814 
6815   if (is_visible_message_reply_info(dialog_id, m)) {
6816     send_update_message_interaction_info(dialog_id, m);
6817   }
6818 }
6819 
get_message_interaction_info_object(DialogId dialog_id,const Message * m) const6820 td_api::object_ptr<td_api::messageInteractionInfo> MessagesManager::get_message_interaction_info_object(
6821     DialogId dialog_id, const Message *m) const {
6822   bool is_visible_reply_info = is_visible_message_reply_info(dialog_id, m);
6823   if (m->view_count == 0 && m->forward_count == 0 && !is_visible_reply_info) {
6824     return nullptr;
6825   }
6826   if (m->message_id.is_scheduled() && (m->forward_info == nullptr || is_broadcast_channel(dialog_id))) {
6827     return nullptr;
6828   }
6829   if (m->message_id.is_local() && m->forward_info == nullptr) {
6830     return nullptr;
6831   }
6832 
6833   td_api::object_ptr<td_api::messageReplyInfo> reply_info;
6834   if (is_visible_reply_info) {
6835     reply_info = m->reply_info.get_message_reply_info_object(td_->contacts_manager_.get(), this);
6836     CHECK(reply_info != nullptr);
6837   }
6838 
6839   return td_api::make_object<td_api::messageInteractionInfo>(m->view_count, m->forward_count, std::move(reply_info));
6840 }
6841 
update_message_interaction_info(DialogId dialog_id,Message * m,int32 view_count,int32 forward_count,bool has_reply_info,MessageReplyInfo && reply_info,const char * source)6842 bool MessagesManager::update_message_interaction_info(DialogId dialog_id, Message *m, int32 view_count,
6843                                                       int32 forward_count, bool has_reply_info,
6844                                                       MessageReplyInfo &&reply_info, const char *source) {
6845   CHECK(m != nullptr);
6846   m->interaction_info_update_date = G()->unix_time();  // doesn't force message saving
6847   if (m->message_id.is_valid_scheduled()) {
6848     has_reply_info = false;
6849   }
6850   bool need_update_reply_info = has_reply_info && m->reply_info.need_update_to(reply_info);
6851   if (has_reply_info && m->reply_info.channel_id == reply_info.channel_id) {
6852     if (need_update_reply_info) {
6853       reply_info.update_max_message_ids(m->reply_info);
6854     } else {
6855       if (m->reply_info.update_max_message_ids(reply_info) && view_count <= m->view_count &&
6856           forward_count <= m->forward_count) {
6857         on_message_reply_info_changed(dialog_id, m);
6858         on_message_changed(get_dialog(dialog_id), m, true, "update_message_interaction_info");
6859       }
6860     }
6861   }
6862   if (view_count > m->view_count || forward_count > m->forward_count || need_update_reply_info) {
6863     LOG(DEBUG) << "Update interaction info of " << FullMessageId{dialog_id, m->message_id} << " from " << m->view_count
6864                << '/' << m->forward_count << "/" << m->reply_info << " to " << view_count << '/' << forward_count << "/"
6865                << reply_info;
6866     bool need_update = false;
6867     if (view_count > m->view_count) {
6868       m->view_count = view_count;
6869       need_update = true;
6870     }
6871     if (forward_count > m->forward_count) {
6872       m->forward_count = forward_count;
6873       need_update = true;
6874     }
6875     if (need_update_reply_info) {
6876       if (m->reply_info.channel_id != reply_info.channel_id) {
6877         if (m->reply_info.channel_id.is_valid() && reply_info.channel_id.is_valid() && m->message_id.is_server()) {
6878           LOG(ERROR) << "Reply info of " << FullMessageId{dialog_id, m->message_id} << " changed from " << m->reply_info
6879                      << " to " << reply_info << " from " << source;
6880         }
6881       }
6882       m->reply_info = std::move(reply_info);
6883       if (!m->top_thread_message_id.is_valid() && !is_broadcast_channel(dialog_id) &&
6884           is_visible_message_reply_info(dialog_id, m)) {
6885         m->top_thread_message_id = m->message_id;
6886       }
6887       need_update |= is_visible_message_reply_info(dialog_id, m);
6888     }
6889     if (need_update) {
6890       send_update_message_interaction_info(dialog_id, m);
6891     }
6892     return true;
6893   }
6894   return false;
6895 }
6896 
on_update_live_location_viewed(FullMessageId full_message_id)6897 void MessagesManager::on_update_live_location_viewed(FullMessageId full_message_id) {
6898   LOG(DEBUG) << "Live location was viewed in " << full_message_id;
6899   if (!are_active_live_location_messages_loaded_) {
6900     get_active_live_location_messages(PromiseCreator::lambda([actor_id = actor_id(this), full_message_id](Unit result) {
6901       send_closure(actor_id, &MessagesManager::on_update_live_location_viewed, full_message_id);
6902     }));
6903     return;
6904   }
6905 
6906   auto active_live_location_message_ids = get_active_live_location_messages(Auto());
6907   if (!td::contains(active_live_location_message_ids, full_message_id)) {
6908     LOG(DEBUG) << "Can't find " << full_message_id << " in " << active_live_location_message_ids;
6909     return;
6910   }
6911 
6912   send_update_message_live_location_viewed(full_message_id);
6913 }
6914 
on_update_some_live_location_viewed(Promise<Unit> && promise)6915 void MessagesManager::on_update_some_live_location_viewed(Promise<Unit> &&promise) {
6916   LOG(DEBUG) << "Some live location was viewed";
6917   if (!are_active_live_location_messages_loaded_) {
6918     get_active_live_location_messages(
6919         PromiseCreator::lambda([actor_id = actor_id(this), promise = std::move(promise)](Unit result) mutable {
6920           send_closure(actor_id, &MessagesManager::on_update_some_live_location_viewed, std::move(promise));
6921         }));
6922     return;
6923   }
6924 
6925   // update all live locations, because it is unknown, which exactly was viewed
6926   auto active_live_location_message_ids = get_active_live_location_messages(Auto());
6927   for (const auto &full_message_id : active_live_location_message_ids) {
6928     send_update_message_live_location_viewed(full_message_id);
6929   }
6930 
6931   promise.set_value(Unit());
6932 }
6933 
need_skip_bot_commands(DialogId dialog_id,const Message * m) const6934 bool MessagesManager::need_skip_bot_commands(DialogId dialog_id, const Message *m) const {
6935   if (td_->auth_manager_->is_bot()) {
6936     return false;
6937   }
6938 
6939   if (m != nullptr && m->message_id.is_scheduled()) {
6940     return true;
6941   }
6942 
6943   auto d = get_dialog(dialog_id);
6944   CHECK(d != nullptr);
6945   return (d->is_has_bots_inited && !d->has_bots) || is_broadcast_channel(dialog_id);
6946 }
6947 
on_external_update_message_content(FullMessageId full_message_id)6948 void MessagesManager::on_external_update_message_content(FullMessageId full_message_id) {
6949   Dialog *d = get_dialog(full_message_id.get_dialog_id());
6950   CHECK(d != nullptr);
6951   Message *m = get_message(d, full_message_id.get_message_id());
6952   CHECK(m != nullptr);
6953   send_update_message_content(d, m, true, "on_external_update_message_content");
6954   if (m->message_id == d->last_message_id) {
6955     send_update_chat_last_message_impl(d, "on_external_update_message_content");
6956   }
6957 }
6958 
update_message_contains_unread_mention(Dialog * d,Message * m,bool contains_unread_mention,const char * source)6959 bool MessagesManager::update_message_contains_unread_mention(Dialog *d, Message *m, bool contains_unread_mention,
6960                                                              const char *source) {
6961   LOG_CHECK(m != nullptr) << source;
6962   CHECK(!m->message_id.is_scheduled());
6963   if (!contains_unread_mention && m->contains_unread_mention) {
6964     remove_message_notification_id(d, m, true, true);  // should be called before contains_unread_mention is updated
6965 
6966     m->contains_unread_mention = false;
6967     if (d->unread_mention_count == 0) {
6968       if (is_dialog_inited(d)) {
6969         LOG(ERROR) << "Unread mention count of " << d->dialog_id << " became negative from " << source;
6970       }
6971     } else {
6972       set_dialog_unread_mention_count(d, d->unread_mention_count - 1);
6973       on_dialog_updated(d->dialog_id, "update_message_contains_unread_mention");
6974     }
6975     LOG(INFO) << "Update unread mention message count in " << d->dialog_id << " to " << d->unread_mention_count
6976               << " by reading " << m->message_id << " from " << source;
6977 
6978     send_closure(G()->td(), &Td::send_update,
6979                  make_tl_object<td_api::updateMessageMentionRead>(d->dialog_id.get(), m->message_id.get(),
6980                                                                   d->unread_mention_count));
6981     return true;
6982   }
6983   return false;
6984 }
6985 
on_read_channel_inbox(ChannelId channel_id,MessageId max_message_id,int32 server_unread_count,int32 pts,const char * source)6986 void MessagesManager::on_read_channel_inbox(ChannelId channel_id, MessageId max_message_id, int32 server_unread_count,
6987                                             int32 pts, const char *source) {
6988   if (td_->auth_manager_->is_bot()) {
6989     return;
6990   }
6991 
6992   CHECK(!max_message_id.is_scheduled());
6993   if (!max_message_id.is_valid() && server_unread_count <= 0) {
6994     return;
6995   }
6996 
6997   DialogId dialog_id(channel_id);
6998   Dialog *d = get_dialog_force(dialog_id, source);
6999   if (d == nullptr) {
7000     LOG(INFO) << "Receive read inbox in unknown " << dialog_id << " from " << source;
7001     return;
7002   }
7003 
7004   /*
7005   // dropping unread count can make things worse, so don't drop it
7006   if (server_unread_count > 0 && G()->parameters().use_message_db && d->is_last_read_inbox_message_id_inited) {
7007     server_unread_count = -1;
7008   }
7009   */
7010 
7011   if (d->pts == pts) {
7012     read_history_inbox(dialog_id, max_message_id, server_unread_count, source);
7013   } else if (d->pts > pts) {
7014     // outdated update, need to repair server_unread_count from the server
7015     repair_channel_server_unread_count(d);
7016   } else {
7017     // update from the future, keep it until it can be applied
7018     if (pts >= d->pending_read_channel_inbox_pts) {
7019       if (d->pending_read_channel_inbox_pts == 0) {
7020         channel_get_difference_retry_timeout_.add_timeout_in(dialog_id.get(), 0.001);
7021       }
7022       d->pending_read_channel_inbox_pts = pts;
7023       d->pending_read_channel_inbox_max_message_id = max_message_id;
7024       d->pending_read_channel_inbox_server_unread_count = server_unread_count;
7025       on_dialog_updated(dialog_id, "on_read_channel_inbox");
7026     }
7027   }
7028 }
7029 
on_read_channel_outbox(ChannelId channel_id,MessageId max_message_id)7030 void MessagesManager::on_read_channel_outbox(ChannelId channel_id, MessageId max_message_id) {
7031   DialogId dialog_id(channel_id);
7032   CHECK(!max_message_id.is_scheduled());
7033   if (max_message_id.is_valid()) {
7034     read_history_outbox(dialog_id, max_message_id);
7035   }
7036 }
7037 
on_update_channel_max_unavailable_message_id(ChannelId channel_id,MessageId max_unavailable_message_id)7038 void MessagesManager::on_update_channel_max_unavailable_message_id(ChannelId channel_id,
7039                                                                    MessageId max_unavailable_message_id) {
7040   if (!channel_id.is_valid()) {
7041     LOG(ERROR) << "Receive max_unavailable_message_id in invalid " << channel_id;
7042     return;
7043   }
7044 
7045   DialogId dialog_id(channel_id);
7046   CHECK(!max_unavailable_message_id.is_scheduled());
7047   if (!max_unavailable_message_id.is_valid() && max_unavailable_message_id != MessageId()) {
7048     LOG(ERROR) << "Receive wrong max_unavailable_message_id: " << max_unavailable_message_id;
7049     max_unavailable_message_id = MessageId();
7050   }
7051   set_dialog_max_unavailable_message_id(dialog_id, max_unavailable_message_id, true,
7052                                         "on_update_channel_max_unavailable_message_id");
7053 }
7054 
on_update_dialog_online_member_count(DialogId dialog_id,int32 online_member_count,bool is_from_server)7055 void MessagesManager::on_update_dialog_online_member_count(DialogId dialog_id, int32 online_member_count,
7056                                                            bool is_from_server) {
7057   if (td_->auth_manager_->is_bot()) {
7058     return;
7059   }
7060 
7061   if (!dialog_id.is_valid()) {
7062     LOG(ERROR) << "Receive number of online members in invalid " << dialog_id;
7063     return;
7064   }
7065 
7066   if (is_broadcast_channel(dialog_id)) {
7067     LOG_IF(ERROR, online_member_count != 0)
7068         << "Receive " << online_member_count << " as a number of online members in a channel " << dialog_id;
7069     return;
7070   }
7071 
7072   if (online_member_count < 0) {
7073     LOG(ERROR) << "Receive " << online_member_count << " as a number of online members in a " << dialog_id;
7074     return;
7075   }
7076 
7077   set_dialog_online_member_count(dialog_id, online_member_count, is_from_server,
7078                                  "on_update_channel_online_member_count");
7079 }
7080 
on_update_delete_scheduled_messages(DialogId dialog_id,vector<ScheduledServerMessageId> && server_message_ids)7081 void MessagesManager::on_update_delete_scheduled_messages(DialogId dialog_id,
7082                                                           vector<ScheduledServerMessageId> &&server_message_ids) {
7083   if (td_->auth_manager_->is_bot()) {
7084     // just in case
7085     return;
7086   }
7087 
7088   if (!dialog_id.is_valid()) {
7089     LOG(ERROR) << "Receive deleted scheduled messages in invalid " << dialog_id;
7090     return;
7091   }
7092 
7093   Dialog *d = get_dialog_force(dialog_id, "on_update_delete_scheduled_messages");
7094   if (d == nullptr) {
7095     LOG(INFO) << "Skip updateDeleteScheduledMessages in unknown " << dialog_id;
7096     return;
7097   }
7098 
7099   vector<int64> deleted_message_ids;
7100   for (auto server_message_id : server_message_ids) {
7101     if (!server_message_id.is_valid()) {
7102       LOG(ERROR) << "Incoming update tries to delete scheduled message " << server_message_id.get();
7103       continue;
7104     }
7105 
7106     auto message = do_delete_scheduled_message(d, MessageId(server_message_id, std::numeric_limits<int32>::max()), true,
7107                                                "on_update_delete_scheduled_messages");
7108     if (message != nullptr) {
7109       deleted_message_ids.push_back(message->message_id.get());
7110     }
7111   }
7112 
7113   send_update_delete_messages(dialog_id, std::move(deleted_message_ids), true, false);
7114 
7115   send_update_chat_has_scheduled_messages(d, true);
7116 }
7117 
on_update_created_public_broadcasts(vector<ChannelId> channel_ids)7118 void MessagesManager::on_update_created_public_broadcasts(vector<ChannelId> channel_ids) {
7119   if (td_->auth_manager_->is_bot()) {
7120     // just in case
7121     return;
7122   }
7123 
7124   if (created_public_broadcasts_inited_ && created_public_broadcasts_ == channel_ids) {
7125     return;
7126   }
7127 
7128   LOG(INFO) << "Update create public channels to " << channel_ids;
7129   for (auto channel_id : channel_ids) {
7130     force_create_dialog(DialogId(channel_id), "on_update_created_public_broadcasts");
7131   }
7132 
7133   created_public_broadcasts_inited_ = true;
7134   created_public_broadcasts_ = std::move(channel_ids);
7135 }
7136 
on_dialog_action(DialogId dialog_id,MessageId top_thread_message_id,DialogId typing_dialog_id,DialogAction action,int32 date,MessageContentType message_content_type)7137 void MessagesManager::on_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, DialogId typing_dialog_id,
7138                                        DialogAction action, int32 date, MessageContentType message_content_type) {
7139   if (td_->auth_manager_->is_bot() || !typing_dialog_id.is_valid()) {
7140     return;
7141   }
7142   if (top_thread_message_id != MessageId() && !top_thread_message_id.is_valid()) {
7143     LOG(ERROR) << "Ignore " << action << " in the message thread of " << top_thread_message_id;
7144     return;
7145   }
7146 
7147   auto dialog_type = dialog_id.get_type();
7148   if (action == DialogAction::get_speaking_action()) {
7149     if ((dialog_type != DialogType::Chat && dialog_type != DialogType::Channel) || top_thread_message_id.is_valid()) {
7150       LOG(ERROR) << "Receive " << action << " in thread of " << top_thread_message_id << " in " << dialog_id;
7151       return;
7152     }
7153     const Dialog *d = get_dialog_force(dialog_id, "on_dialog_action");
7154     if (d != nullptr && d->active_group_call_id.is_valid()) {
7155       auto group_call_id = td_->group_call_manager_->get_group_call_id(d->active_group_call_id, dialog_id);
7156       td_->group_call_manager_->on_user_speaking_in_group_call(group_call_id, typing_dialog_id, date);
7157     }
7158     return;
7159   }
7160 
7161   if (is_broadcast_channel(dialog_id)) {
7162     return;
7163   }
7164 
7165   auto typing_dialog_type = typing_dialog_id.get_type();
7166   if (typing_dialog_type != DialogType::User && dialog_type != DialogType::Chat && dialog_type != DialogType::Channel) {
7167     LOG(ERROR) << "Ignore " << action << " of " << typing_dialog_id << " in " << dialog_id;
7168     return;
7169   }
7170 
7171   {
7172     auto message_import_progress = action.get_importing_messages_action_progress();
7173     if (message_import_progress >= 0) {
7174       // TODO
7175       return;
7176     }
7177   }
7178 
7179   {
7180     auto clicking_info = action.get_clicking_animated_emoji_action_info();
7181     if (!clicking_info.data.empty()) {
7182       if (date > G()->unix_time() - 10 && dialog_type == DialogType::User && dialog_id == typing_dialog_id) {
7183         FullMessageId full_message_id{dialog_id, MessageId(ServerMessageId(clicking_info.message_id))};
7184         auto *m = get_message_force(full_message_id, "on_dialog_action");
7185         if (m != nullptr) {
7186           on_message_content_animated_emoji_clicked(m->content.get(), full_message_id, td_, clicking_info.emoji,
7187                                                     std::move(clicking_info.data));
7188         }
7189       }
7190       return;
7191     }
7192   }
7193 
7194   if (is_unsent_animated_emoji_click(td_, dialog_id, action)) {
7195     LOG(DEBUG) << "Ignore unsent " << action;
7196     return;
7197   }
7198 
7199   if (!have_dialog(dialog_id)) {
7200     LOG(DEBUG) << "Ignore " << action << " in unknown " << dialog_id;
7201     return;
7202   }
7203 
7204   if (typing_dialog_type == DialogType::User) {
7205     if (!td_->contacts_manager_->have_min_user(typing_dialog_id.get_user_id())) {
7206       LOG(DEBUG) << "Ignore " << action << " of unknown " << typing_dialog_id.get_user_id();
7207       return;
7208     }
7209   } else {
7210     if (!have_dialog_info_force(typing_dialog_id)) {
7211       LOG(DEBUG) << "Ignore " << action << " of unknown " << typing_dialog_id;
7212       return;
7213     }
7214     force_create_dialog(typing_dialog_id, "on_dialog_action", true);
7215     if (!have_dialog(typing_dialog_id)) {
7216       LOG(ERROR) << "Failed to create typing " << typing_dialog_id;
7217       return;
7218     }
7219   }
7220 
7221   bool is_canceled = action == DialogAction();
7222   if ((!is_canceled || message_content_type != MessageContentType::None) && typing_dialog_type == DialogType::User) {
7223     td_->contacts_manager_->on_update_user_local_was_online(typing_dialog_id.get_user_id(), date);
7224   }
7225 
7226   if (dialog_type == DialogType::User || dialog_type == DialogType::SecretChat) {
7227     CHECK(typing_dialog_type == DialogType::User);
7228     auto user_id = typing_dialog_id.get_user_id();
7229     if (!td_->contacts_manager_->is_user_bot(user_id) && !td_->contacts_manager_->is_user_status_exact(user_id) &&
7230         !get_dialog(dialog_id)->is_opened && !is_canceled) {
7231       return;
7232     }
7233   }
7234 
7235   if (is_canceled) {
7236     auto actions_it = active_dialog_actions_.find(dialog_id);
7237     if (actions_it == active_dialog_actions_.end()) {
7238       return;
7239     }
7240 
7241     auto &active_actions = actions_it->second;
7242     auto it = std::find_if(
7243         active_actions.begin(), active_actions.end(),
7244         [typing_dialog_id](const ActiveDialogAction &action) { return action.typing_dialog_id == typing_dialog_id; });
7245     if (it == active_actions.end()) {
7246       return;
7247     }
7248 
7249     if (!(typing_dialog_type == DialogType::User &&
7250           td_->contacts_manager_->is_user_bot(typing_dialog_id.get_user_id())) &&
7251         !it->action.is_canceled_by_message_of_type(message_content_type)) {
7252       return;
7253     }
7254 
7255     LOG(DEBUG) << "Cancel action of " << typing_dialog_id << " in " << dialog_id;
7256     top_thread_message_id = it->top_thread_message_id;
7257     active_actions.erase(it);
7258     if (active_actions.empty()) {
7259       active_dialog_actions_.erase(dialog_id);
7260       LOG(DEBUG) << "Cancel action timeout in " << dialog_id;
7261       active_dialog_action_timeout_.cancel_timeout(dialog_id.get());
7262     }
7263   } else {
7264     if (date < G()->unix_time_cached() - DIALOG_ACTION_TIMEOUT - 60) {
7265       LOG(DEBUG) << "Ignore too old action of " << typing_dialog_id << " in " << dialog_id << " sent at " << date;
7266       return;
7267     }
7268     auto &active_actions = active_dialog_actions_[dialog_id];
7269     auto it = std::find_if(
7270         active_actions.begin(), active_actions.end(),
7271         [typing_dialog_id](const ActiveDialogAction &action) { return action.typing_dialog_id == typing_dialog_id; });
7272     MessageId prev_top_thread_message_id;
7273     DialogAction prev_action;
7274     if (it != active_actions.end()) {
7275       LOG(DEBUG) << "Re-add action of " << typing_dialog_id << " in " << dialog_id;
7276       prev_top_thread_message_id = it->top_thread_message_id;
7277       prev_action = it->action;
7278       active_actions.erase(it);
7279     } else {
7280       LOG(DEBUG) << "Add action of " << typing_dialog_id << " in " << dialog_id;
7281     }
7282 
7283     active_actions.emplace_back(top_thread_message_id, typing_dialog_id, action, Time::now());
7284     if (top_thread_message_id == prev_top_thread_message_id && action == prev_action) {
7285       return;
7286     }
7287     if (top_thread_message_id != prev_top_thread_message_id && prev_top_thread_message_id.is_valid()) {
7288       send_update_chat_action(dialog_id, prev_top_thread_message_id, typing_dialog_id, DialogAction());
7289     }
7290     if (active_actions.size() == 1u) {
7291       LOG(DEBUG) << "Set action timeout in " << dialog_id;
7292       active_dialog_action_timeout_.set_timeout_in(dialog_id.get(), DIALOG_ACTION_TIMEOUT);
7293     }
7294   }
7295 
7296   if (top_thread_message_id.is_valid()) {
7297     send_update_chat_action(dialog_id, MessageId(), typing_dialog_id, action);
7298   }
7299   send_update_chat_action(dialog_id, top_thread_message_id, typing_dialog_id, action);
7300 }
7301 
cancel_dialog_action(DialogId dialog_id,const Message * m)7302 void MessagesManager::cancel_dialog_action(DialogId dialog_id, const Message *m) {
7303   CHECK(m != nullptr);
7304   if (td_->auth_manager_->is_bot() || m->forward_info != nullptr || m->had_forward_info ||
7305       m->via_bot_user_id.is_valid() || m->hide_via_bot || m->is_channel_post || m->message_id.is_scheduled()) {
7306     return;
7307   }
7308 
7309   on_dialog_action(dialog_id, MessageId(), get_message_sender(m), DialogAction(), m->date, m->content->get_type());
7310 }
7311 
add_postponed_channel_update(DialogId dialog_id,tl_object_ptr<telegram_api::Update> && update,int32 new_pts,int32 pts_count,Promise<Unit> && promise)7312 void MessagesManager::add_postponed_channel_update(DialogId dialog_id, tl_object_ptr<telegram_api::Update> &&update,
7313                                                    int32 new_pts, int32 pts_count, Promise<Unit> &&promise) {
7314   postponed_channel_updates_[dialog_id].emplace(
7315       new_pts, PendingPtsUpdate(std::move(update), new_pts, pts_count, std::move(promise)));
7316 }
7317 
add_pending_channel_update(DialogId dialog_id,tl_object_ptr<telegram_api::Update> && update,int32 new_pts,int32 pts_count,Promise<Unit> && promise,const char * source,bool is_postponed_update)7318 void MessagesManager::add_pending_channel_update(DialogId dialog_id, tl_object_ptr<telegram_api::Update> &&update,
7319                                                  int32 new_pts, int32 pts_count, Promise<Unit> &&promise,
7320                                                  const char *source, bool is_postponed_update) {
7321   LOG(INFO) << "Receive from " << source << " pending " << to_string(update);
7322   CHECK(update != nullptr);
7323   if (dialog_id.get_type() != DialogType::Channel) {
7324     LOG(ERROR) << "Receive channel update in invalid " << dialog_id << " from " << source << ": "
7325                << oneline(to_string(update));
7326     promise.set_value(Unit());
7327     return;
7328   }
7329   if (pts_count < 0 || new_pts <= pts_count) {
7330     LOG(ERROR) << "Receive channel update from " << source << " with wrong pts = " << new_pts
7331                << " or pts_count = " << pts_count << ": " << oneline(to_string(update));
7332     promise.set_value(Unit());
7333     return;
7334   }
7335 
7336   auto channel_id = dialog_id.get_channel_id();
7337   if (!td_->contacts_manager_->have_channel(channel_id) && td_->contacts_manager_->have_min_channel(channel_id)) {
7338     td_->updates_manager_->schedule_get_difference("add_pending_channel_update 1");
7339     promise.set_value(Unit());
7340     return;
7341   }
7342 
7343   // TODO need to save all updates that can change result of running queries not associated with pts (for example
7344   // getHistory) and apply them to result of these queries
7345 
7346   Dialog *d = get_dialog_force(dialog_id, "add_pending_channel_update 2");
7347   if (d == nullptr) {
7348     auto pts = load_channel_pts(dialog_id);
7349     if (pts > 0) {
7350       if (!td_->contacts_manager_->have_channel(channel_id)) {
7351         // do not create dialog if there is no info about the channel
7352         LOG(INFO) << "There is no info about " << channel_id << ", so ignore " << oneline(to_string(update));
7353         promise.set_value(Unit());
7354         return;
7355       }
7356 
7357       if (new_pts <= pts && new_pts >= pts - 19999) {
7358         LOG(INFO) << "There is no need to process an update with pts " << new_pts << " in " << dialog_id << " with pts "
7359                   << pts;
7360         promise.set_value(Unit());
7361         return;
7362       }
7363 
7364       if (new_pts > pts && pts != new_pts - pts_count) {
7365         LOG(INFO) << "Found a gap in unknown " << dialog_id << " with pts = " << pts << ". new_pts = " << new_pts
7366                   << ", pts_count = " << pts_count << " in update from " << source;
7367         add_postponed_channel_update(dialog_id, std::move(update), new_pts, pts_count, std::move(promise));
7368         get_channel_difference(dialog_id, pts, true, "add_pending_channel_update 3");
7369         return;
7370       }
7371 
7372       d = add_dialog(dialog_id, "add_pending_channel_update 4");
7373       CHECK(d != nullptr);
7374       CHECK(d->pts == pts);
7375       update_dialog_pos(d, "add_pending_channel_update 5");
7376     }
7377   }
7378   if (d == nullptr) {
7379     // if there is no dialog, it can be created by the update
7380     LOG(INFO) << "Receive pending update from " << source << " about unknown " << dialog_id;
7381     if (running_get_channel_difference(dialog_id)) {
7382       add_postponed_channel_update(dialog_id, std::move(update), new_pts, pts_count, std::move(promise));
7383       return;
7384     }
7385   } else {
7386     int32 old_pts = d->pts;
7387     if (new_pts <= old_pts) {  // very old or unuseful update
7388       if (new_pts < old_pts - 19999 && !is_postponed_update) {
7389         // restore channel pts after delete_first_messages
7390         auto now = Time::now();
7391         if (now > last_channel_pts_jump_warning_time_ + 1) {
7392           LOG(ERROR) << "Restore pts in " << d->dialog_id << " from " << source << " after delete_first_messages from "
7393                      << old_pts << " to " << new_pts << " is temporarily disabled, pts_count = " << pts_count
7394                      << ", update is from " << source << ": " << oneline(to_string(update));
7395           last_channel_pts_jump_warning_time_ = now;
7396         }
7397         get_channel_difference(dialog_id, old_pts, true, "add_pending_channel_update old");
7398       }
7399 
7400       if (update->get_id() == telegram_api::updateNewChannelMessage::ID) {
7401         auto update_new_channel_message = static_cast<telegram_api::updateNewChannelMessage *>(update.get());
7402         auto message_id = get_message_id(update_new_channel_message->message_, false);
7403         FullMessageId full_message_id(dialog_id, message_id);
7404         if (update_message_ids_.find(full_message_id) != update_message_ids_.end()) {
7405           // apply sent channel message
7406           on_get_message(std::move(update_new_channel_message->message_), true, true, false, true, true,
7407                          "updateNewChannelMessage with an awaited message");
7408           promise.set_value(Unit());
7409           return;
7410         }
7411       }
7412       if (update->get_id() == updateSentMessage::ID) {
7413         auto update_sent_message = static_cast<updateSentMessage *>(update.get());
7414         if (being_sent_messages_.count(update_sent_message->random_id_) > 0) {
7415           // apply sent channel message
7416           on_send_message_success(update_sent_message->random_id_, update_sent_message->message_id_,
7417                                   update_sent_message->date_, update_sent_message->ttl_period_, FileId(),
7418                                   "process old updateSentChannelMessage");
7419           promise.set_value(Unit());
7420           return;
7421         }
7422       }
7423 
7424       LOG_IF(WARNING, new_pts == old_pts && pts_count == 0)
7425           << "Receive from " << source << " useless channel update " << oneline(to_string(update));
7426       LOG(INFO) << "Skip already applied channel update";
7427       promise.set_value(Unit());
7428       return;
7429     }
7430 
7431     if (running_get_channel_difference(dialog_id)) {
7432       LOG(INFO) << "Postpone channel update, because getChannelDifference is run";
7433       add_postponed_channel_update(dialog_id, std::move(update), new_pts, pts_count, std::move(promise));
7434       return;
7435     }
7436 
7437     if (old_pts != new_pts - pts_count) {
7438       LOG(INFO) << "Found a gap in the " << dialog_id << " with pts = " << old_pts << ". new_pts = " << new_pts
7439                 << ", pts_count = " << pts_count << " in update from " << source;
7440       if (d->was_opened || td_->contacts_manager_->get_channel_status(channel_id).is_member() ||
7441           is_dialog_sponsored(d)) {
7442         add_postponed_channel_update(dialog_id, std::move(update), new_pts, pts_count, std::move(promise));
7443         get_channel_difference(dialog_id, old_pts, true, "add_pending_channel_update pts mismatch");
7444       } else {
7445         promise.set_value(Unit());
7446       }
7447       return;
7448     }
7449   }
7450 
7451   if (d == nullptr || pts_count > 0) {
7452     process_channel_update(std::move(update));
7453     LOG_CHECK(!running_get_channel_difference(dialog_id)) << '"' << active_get_channel_differencies_[dialog_id] << '"';
7454   } else {
7455     LOG_IF(INFO, update->get_id() != dummyUpdate::ID)
7456         << "Skip useless channel update from " << source << ": " << to_string(update);
7457   }
7458 
7459   if (d == nullptr) {
7460     d = get_dialog(dialog_id);
7461     if (d == nullptr) {
7462       LOG(INFO) << "Update didn't created " << dialog_id;
7463       promise.set_value(Unit());
7464       return;
7465     }
7466   }
7467 
7468   CHECK(new_pts > d->pts);
7469   set_channel_pts(d, new_pts, source);
7470   promise.set_value(Unit());
7471 }
7472 
is_old_channel_update(DialogId dialog_id,int32 new_pts)7473 bool MessagesManager::is_old_channel_update(DialogId dialog_id, int32 new_pts) {
7474   CHECK(dialog_id.get_type() == DialogType::Channel);
7475 
7476   const Dialog *d = get_dialog_force(dialog_id, "is_old_channel_update");
7477   return new_pts <= (d == nullptr ? load_channel_pts(dialog_id) : d->pts);
7478 }
7479 
process_pts_update(tl_object_ptr<telegram_api::Update> && update)7480 void MessagesManager::process_pts_update(tl_object_ptr<telegram_api::Update> &&update) {
7481   switch (update->get_id()) {
7482     case dummyUpdate::ID:
7483       LOG(INFO) << "Process dummyUpdate";
7484       break;
7485     case telegram_api::updateNewMessage::ID: {
7486       auto update_new_message = move_tl_object_as<telegram_api::updateNewMessage>(update);
7487       LOG(INFO) << "Process updateNewMessage";
7488       on_get_message(std::move(update_new_message->message_), true, false, false, true, true, "updateNewMessage");
7489       break;
7490     }
7491     case updateSentMessage::ID: {
7492       auto update_sent_message = move_tl_object_as<updateSentMessage>(update);
7493       LOG(INFO) << "Process updateSentMessage " << update_sent_message->random_id_;
7494       on_send_message_success(update_sent_message->random_id_, update_sent_message->message_id_,
7495                               update_sent_message->date_, update_sent_message->ttl_period_, FileId(),
7496                               "process updateSentMessage");
7497       break;
7498     }
7499     case telegram_api::updateReadMessagesContents::ID: {
7500       auto read_contents_update = move_tl_object_as<telegram_api::updateReadMessagesContents>(update);
7501       LOG(INFO) << "Process updateReadMessageContents";
7502       for (auto &message_id : read_contents_update->messages_) {
7503         read_message_content_from_updates(MessageId(ServerMessageId(message_id)));
7504       }
7505       break;
7506     }
7507     case telegram_api::updateEditMessage::ID: {
7508       auto update_edit_message = move_tl_object_as<telegram_api::updateEditMessage>(update);
7509       auto full_message_id = on_get_message(std::move(update_edit_message->message_), false, false, false, false, false,
7510                                             "updateEditMessage");
7511       LOG(INFO) << "Process updateEditMessage";
7512       on_message_edited(full_message_id, update_edit_message->pts_);
7513       break;
7514     }
7515     case telegram_api::updateDeleteMessages::ID: {
7516       auto delete_update = move_tl_object_as<telegram_api::updateDeleteMessages>(update);
7517       LOG(INFO) << "Process updateDeleteMessages";
7518       vector<MessageId> message_ids;
7519       for (auto message : delete_update->messages_) {
7520         message_ids.push_back(MessageId(ServerMessageId(message)));
7521       }
7522       delete_messages_from_updates(message_ids);
7523       break;
7524     }
7525     case telegram_api::updateReadHistoryInbox::ID: {
7526       auto read_update = move_tl_object_as<telegram_api::updateReadHistoryInbox>(update);
7527       LOG(INFO) << "Process updateReadHistoryInbox";
7528       DialogId dialog_id(read_update->peer_);
7529       FolderId folder_id;
7530       if ((read_update->flags_ & telegram_api::updateReadHistoryInbox::FOLDER_ID_MASK) != 0) {
7531         folder_id = FolderId(read_update->folder_id_);
7532       }
7533       on_update_dialog_folder_id(dialog_id, folder_id);
7534       read_history_inbox(dialog_id, MessageId(ServerMessageId(read_update->max_id_)),
7535                          -1 /*read_update->still_unread_count*/, "updateReadHistoryInbox");
7536       break;
7537     }
7538     case telegram_api::updateReadHistoryOutbox::ID: {
7539       auto read_update = move_tl_object_as<telegram_api::updateReadHistoryOutbox>(update);
7540       LOG(INFO) << "Process updateReadHistoryOutbox";
7541       read_history_outbox(DialogId(read_update->peer_), MessageId(ServerMessageId(read_update->max_id_)));
7542       break;
7543     }
7544     case telegram_api::updatePinnedMessages::ID: {
7545       auto pinned_messages_update = move_tl_object_as<telegram_api::updatePinnedMessages>(update);
7546       LOG(INFO) << "Process updatePinnedMessages";
7547       vector<MessageId> message_ids;
7548       for (auto message : pinned_messages_update->messages_) {
7549         message_ids.push_back(MessageId(ServerMessageId(message)));
7550       }
7551       update_dialog_pinned_messages_from_updates(DialogId(pinned_messages_update->peer_), message_ids,
7552                                                  pinned_messages_update->pinned_);
7553       break;
7554     }
7555     default:
7556       UNREACHABLE();
7557   }
7558   CHECK(!td_->updates_manager_->running_get_difference());
7559 }
7560 
process_channel_update(tl_object_ptr<telegram_api::Update> && update)7561 void MessagesManager::process_channel_update(tl_object_ptr<telegram_api::Update> &&update) {
7562   switch (update->get_id()) {
7563     case dummyUpdate::ID:
7564       LOG(INFO) << "Process dummyUpdate";
7565       break;
7566     case updateSentMessage::ID: {
7567       auto update_sent_message = move_tl_object_as<updateSentMessage>(update);
7568       LOG(INFO) << "Process updateSentMessage " << update_sent_message->random_id_;
7569       on_send_message_success(update_sent_message->random_id_, update_sent_message->message_id_,
7570                               update_sent_message->date_, update_sent_message->ttl_period_, FileId(),
7571                               "process updateSentChannelMessage");
7572       break;
7573     }
7574     case telegram_api::updateNewChannelMessage::ID: {
7575       auto update_new_channel_message = move_tl_object_as<telegram_api::updateNewChannelMessage>(update);
7576       LOG(INFO) << "Process updateNewChannelMessage";
7577       on_get_message(std::move(update_new_channel_message->message_), true, true, false, true, true,
7578                      "updateNewChannelMessage");
7579       break;
7580     }
7581     case telegram_api::updateDeleteChannelMessages::ID: {
7582       auto delete_channel_messages_update = move_tl_object_as<telegram_api::updateDeleteChannelMessages>(update);
7583       LOG(INFO) << "Process updateDeleteChannelMessages";
7584       ChannelId channel_id(delete_channel_messages_update->channel_id_);
7585       if (!channel_id.is_valid()) {
7586         LOG(ERROR) << "Receive invalid " << channel_id;
7587         break;
7588       }
7589 
7590       vector<MessageId> message_ids;
7591       for (auto &message : delete_channel_messages_update->messages_) {
7592         message_ids.push_back(MessageId(ServerMessageId(message)));
7593       }
7594 
7595       auto dialog_id = DialogId(channel_id);
7596       delete_dialog_messages(dialog_id, message_ids, true, false, "updateDeleteChannelMessages");
7597       break;
7598     }
7599     case telegram_api::updateEditChannelMessage::ID: {
7600       auto update_edit_channel_message = move_tl_object_as<telegram_api::updateEditChannelMessage>(update);
7601       LOG(INFO) << "Process updateEditChannelMessage";
7602       auto full_message_id = on_get_message(std::move(update_edit_channel_message->message_), false, true, false, false,
7603                                             false, "updateEditChannelMessage");
7604       on_message_edited(full_message_id, update_edit_channel_message->pts_);
7605       break;
7606     }
7607     case telegram_api::updatePinnedChannelMessages::ID: {
7608       auto pinned_channel_messages_update = move_tl_object_as<telegram_api::updatePinnedChannelMessages>(update);
7609       LOG(INFO) << "Process updatePinnedChannelMessages";
7610       ChannelId channel_id(pinned_channel_messages_update->channel_id_);
7611       if (!channel_id.is_valid()) {
7612         LOG(ERROR) << "Receive invalid " << channel_id;
7613         break;
7614       }
7615 
7616       vector<MessageId> message_ids;
7617       for (auto &message : pinned_channel_messages_update->messages_) {
7618         message_ids.push_back(MessageId(ServerMessageId(message)));
7619       }
7620 
7621       update_dialog_pinned_messages_from_updates(DialogId(channel_id), message_ids,
7622                                                  pinned_channel_messages_update->pinned_);
7623       break;
7624     }
7625     default:
7626       UNREACHABLE();
7627   }
7628 }
7629 
on_message_edited(FullMessageId full_message_id,int32 pts)7630 void MessagesManager::on_message_edited(FullMessageId full_message_id, int32 pts) {
7631   if (full_message_id == FullMessageId()) {
7632     return;
7633   }
7634 
7635   auto dialog_id = full_message_id.get_dialog_id();
7636   Dialog *d = get_dialog(dialog_id);
7637   Message *m = get_message(d, full_message_id.get_message_id());
7638   CHECK(m != nullptr);
7639   m->last_edit_pts = pts;
7640   if (td_->auth_manager_->is_bot()) {
7641     d->last_edited_message_id = m->message_id;
7642     send_update_message_edited(dialog_id, m);
7643   }
7644   update_used_hashtags(dialog_id, m);
7645 }
7646 
get_notification_settings_scope_database_key(NotificationSettingsScope scope)7647 string MessagesManager::get_notification_settings_scope_database_key(NotificationSettingsScope scope) {
7648   switch (scope) {
7649     case NotificationSettingsScope::Private:
7650       return "nsfpc";
7651     case NotificationSettingsScope::Group:
7652       return "nsfgc";
7653     case NotificationSettingsScope::Channel:
7654       return "nsfcc";
7655     default:
7656       UNREACHABLE();
7657       return "";
7658   }
7659 }
7660 
save_scope_notification_settings(NotificationSettingsScope scope,const ScopeNotificationSettings & new_settings)7661 void MessagesManager::save_scope_notification_settings(NotificationSettingsScope scope,
7662                                                        const ScopeNotificationSettings &new_settings) {
7663   string key = get_notification_settings_scope_database_key(scope);
7664   G()->td_db()->get_binlog_pmc()->set(key, log_event_store(new_settings).as_slice().str());
7665 }
7666 
update_dialog_notification_settings(DialogId dialog_id,DialogNotificationSettings * current_settings,const DialogNotificationSettings & new_settings)7667 bool MessagesManager::update_dialog_notification_settings(DialogId dialog_id,
7668                                                           DialogNotificationSettings *current_settings,
7669                                                           const DialogNotificationSettings &new_settings) {
7670   if (td_->auth_manager_->is_bot()) {
7671     // just in case
7672     return false;
7673   }
7674 
7675   bool need_update_server = current_settings->mute_until != new_settings.mute_until ||
7676                             current_settings->sound != new_settings.sound ||
7677                             current_settings->show_preview != new_settings.show_preview ||
7678                             current_settings->use_default_mute_until != new_settings.use_default_mute_until ||
7679                             current_settings->use_default_sound != new_settings.use_default_sound ||
7680                             current_settings->use_default_show_preview != new_settings.use_default_show_preview;
7681   bool need_update_local =
7682       current_settings->use_default_disable_pinned_message_notifications !=
7683           new_settings.use_default_disable_pinned_message_notifications ||
7684       current_settings->disable_pinned_message_notifications != new_settings.disable_pinned_message_notifications ||
7685       current_settings->use_default_disable_mention_notifications !=
7686           new_settings.use_default_disable_mention_notifications ||
7687       current_settings->disable_mention_notifications != new_settings.disable_mention_notifications;
7688 
7689   bool is_changed = need_update_server || need_update_local ||
7690                     current_settings->is_synchronized != new_settings.is_synchronized ||
7691                     current_settings->is_use_default_fixed != new_settings.is_use_default_fixed;
7692 
7693   if (is_changed) {
7694     Dialog *d = get_dialog(dialog_id);
7695     LOG_CHECK(d != nullptr) << "Wrong " << dialog_id << " in update_dialog_notification_settings";
7696     bool was_dialog_mentions_disabled = is_dialog_mention_notifications_disabled(d);
7697 
7698     VLOG(notifications) << "Update notification settings in " << dialog_id << " from " << *current_settings << " to "
7699                         << new_settings;
7700 
7701     update_dialog_unmute_timeout(d, current_settings->use_default_mute_until, current_settings->mute_until,
7702                                  new_settings.use_default_mute_until, new_settings.mute_until);
7703 
7704     *current_settings = new_settings;
7705     on_dialog_updated(dialog_id, "update_dialog_notification_settings");
7706 
7707     if (is_dialog_muted(d)) {
7708       // no check for was_muted to clean pending message notifications in chats with unsynchronized settings
7709       remove_all_dialog_notifications(d, false, "update_dialog_notification_settings 2");
7710     }
7711     if (is_dialog_pinned_message_notifications_disabled(d) && d->mention_notification_group.group_id.is_valid() &&
7712         d->pinned_message_notification_message_id.is_valid()) {
7713       remove_dialog_pinned_message_notification(d, "update_dialog_notification_settings 3");
7714     }
7715     if (was_dialog_mentions_disabled != is_dialog_mention_notifications_disabled(d)) {
7716       if (was_dialog_mentions_disabled) {
7717         update_dialog_mention_notification_count(d);
7718       } else {
7719         remove_dialog_mention_notifications(d);
7720       }
7721     }
7722 
7723     if (need_update_server || need_update_local) {
7724       send_closure(G()->td(), &Td::send_update,
7725                    make_tl_object<td_api::updateChatNotificationSettings>(
7726                        dialog_id.get(), get_chat_notification_settings_object(current_settings)));
7727     }
7728   }
7729   return need_update_server;
7730 }
7731 
update_scope_notification_settings(NotificationSettingsScope scope,ScopeNotificationSettings * current_settings,const ScopeNotificationSettings & new_settings)7732 bool MessagesManager::update_scope_notification_settings(NotificationSettingsScope scope,
7733                                                          ScopeNotificationSettings *current_settings,
7734                                                          const ScopeNotificationSettings &new_settings) {
7735   if (td_->auth_manager_->is_bot()) {
7736     // just in case
7737     return false;
7738   }
7739 
7740   bool need_update_server = current_settings->mute_until != new_settings.mute_until ||
7741                             current_settings->sound != new_settings.sound ||
7742                             current_settings->show_preview != new_settings.show_preview;
7743   bool need_update_local =
7744       current_settings->disable_pinned_message_notifications != new_settings.disable_pinned_message_notifications ||
7745       current_settings->disable_mention_notifications != new_settings.disable_mention_notifications;
7746   bool was_inited = current_settings->is_synchronized;
7747   bool is_inited = new_settings.is_synchronized;
7748   if (was_inited && !is_inited) {
7749     return false;  // just in case
7750   }
7751   bool is_changed = need_update_server || need_update_local || was_inited != is_inited;
7752   if (is_changed) {
7753     save_scope_notification_settings(scope, new_settings);
7754 
7755     VLOG(notifications) << "Update notification settings in " << scope << " from " << *current_settings << " to "
7756                         << new_settings;
7757 
7758     update_scope_unmute_timeout(scope, current_settings->mute_until, new_settings.mute_until);
7759 
7760     if (!current_settings->disable_pinned_message_notifications && new_settings.disable_pinned_message_notifications) {
7761       VLOG(notifications) << "Remove pinned message notifications in " << scope;
7762       for (auto &dialog : dialogs_) {
7763         Dialog *d = dialog.second.get();
7764         if (d->notification_settings.use_default_disable_pinned_message_notifications &&
7765             d->mention_notification_group.group_id.is_valid() && d->pinned_message_notification_message_id.is_valid() &&
7766             get_dialog_notification_setting_scope(d->dialog_id) == scope) {
7767           remove_dialog_pinned_message_notification(d, "update_scope_notification_settings");
7768         }
7769       }
7770     }
7771     if (current_settings->disable_mention_notifications != new_settings.disable_mention_notifications) {
7772       VLOG(notifications) << "Remove mention notifications in " << scope;
7773       for (auto &dialog : dialogs_) {
7774         Dialog *d = dialog.second.get();
7775         if (d->notification_settings.use_default_disable_mention_notifications &&
7776             get_dialog_notification_setting_scope(d->dialog_id) == scope) {
7777           if (current_settings->disable_mention_notifications) {
7778             update_dialog_mention_notification_count(d);
7779           } else {
7780             remove_dialog_mention_notifications(d);
7781           }
7782         }
7783       }
7784     }
7785 
7786     *current_settings = new_settings;
7787 
7788     send_closure(G()->td(), &Td::send_update, get_update_scope_notification_settings_object(scope));
7789   }
7790   return need_update_server;
7791 }
7792 
schedule_dialog_unmute(DialogId dialog_id,bool use_default,int32 mute_until)7793 void MessagesManager::schedule_dialog_unmute(DialogId dialog_id, bool use_default, int32 mute_until) {
7794   auto now = G()->unix_time_cached();
7795   if (!use_default && mute_until >= now && mute_until < now + 366 * 86400) {
7796     dialog_unmute_timeout_.set_timeout_in(dialog_id.get(), mute_until - now + 1);
7797   } else {
7798     dialog_unmute_timeout_.cancel_timeout(dialog_id.get());
7799   }
7800 }
7801 
update_dialog_unmute_timeout(Dialog * d,bool & old_use_default,int32 & old_mute_until,bool new_use_default,int32 new_mute_until)7802 void MessagesManager::update_dialog_unmute_timeout(Dialog *d, bool &old_use_default, int32 &old_mute_until,
7803                                                    bool new_use_default, int32 new_mute_until) {
7804   if (td_->auth_manager_->is_bot()) {
7805     // just in case
7806     return;
7807   }
7808 
7809   if (old_use_default == new_use_default && old_mute_until == new_mute_until) {
7810     return;
7811   }
7812   CHECK(d != nullptr);
7813   CHECK(old_mute_until >= 0);
7814 
7815   schedule_dialog_unmute(d->dialog_id, new_use_default, new_mute_until);
7816 
7817   bool was_muted = (old_use_default ? get_scope_mute_until(d->dialog_id) : old_mute_until) != 0;
7818   bool is_muted = (new_use_default ? get_scope_mute_until(d->dialog_id) : new_mute_until) != 0;
7819   if (was_muted != is_muted && need_unread_counter(d->order)) {
7820     auto unread_count = d->server_unread_count + d->local_unread_count;
7821     if (unread_count != 0 || d->is_marked_as_unread) {
7822       for (auto &list : get_dialog_lists(d)) {
7823         if (unread_count != 0 && list.is_message_unread_count_inited_) {
7824           int32 delta = was_muted ? -unread_count : unread_count;
7825           list.unread_message_muted_count_ += delta;
7826           send_update_unread_message_count(list, d->dialog_id, true, "update_dialog_unmute_timeout");
7827         }
7828         if (list.is_dialog_unread_count_inited_) {
7829           int32 delta = was_muted ? -1 : 1;
7830           list.unread_dialog_muted_count_ += delta;
7831           if (unread_count == 0 && d->is_marked_as_unread) {
7832             list.unread_dialog_muted_marked_count_ += delta;
7833           }
7834           send_update_unread_chat_count(list, d->dialog_id, true, "update_dialog_unmute_timeout");
7835         }
7836       }
7837     }
7838   }
7839 
7840   old_use_default = new_use_default;
7841   old_mute_until = new_mute_until;
7842 
7843   if (was_muted != is_muted && !dialog_filters_.empty()) {
7844     update_dialog_lists(d, get_dialog_positions(d), true, false, "update_dialog_unmute_timeout");
7845   }
7846 }
7847 
schedule_scope_unmute(NotificationSettingsScope scope,int32 mute_until)7848 void MessagesManager::schedule_scope_unmute(NotificationSettingsScope scope, int32 mute_until) {
7849   auto now = G()->unix_time_cached();
7850   if (mute_until >= now && mute_until < now + 366 * 86400) {
7851     dialog_unmute_timeout_.set_timeout_in(static_cast<int64>(scope) + 1, mute_until - now + 1);
7852   } else {
7853     dialog_unmute_timeout_.cancel_timeout(static_cast<int64>(scope) + 1);
7854   }
7855 }
7856 
update_scope_unmute_timeout(NotificationSettingsScope scope,int32 & old_mute_until,int32 new_mute_until)7857 void MessagesManager::update_scope_unmute_timeout(NotificationSettingsScope scope, int32 &old_mute_until,
7858                                                   int32 new_mute_until) {
7859   if (td_->auth_manager_->is_bot()) {
7860     // just in case
7861     return;
7862   }
7863 
7864   LOG(INFO) << "Update " << scope << " unmute timeout from " << old_mute_until << " to " << new_mute_until;
7865   if (old_mute_until == new_mute_until) {
7866     return;
7867   }
7868   CHECK(old_mute_until >= 0);
7869 
7870   schedule_scope_unmute(scope, new_mute_until);
7871 
7872   auto was_muted = old_mute_until != 0;
7873   auto is_muted = new_mute_until != 0;
7874   if (was_muted != is_muted) {
7875     if (G()->parameters().use_message_db) {
7876       std::unordered_map<DialogListId, int32, DialogListIdHash> delta;
7877       std::unordered_map<DialogListId, int32, DialogListIdHash> total_count;
7878       std::unordered_map<DialogListId, int32, DialogListIdHash> marked_count;
7879       std::unordered_set<DialogListId, DialogListIdHash> dialog_list_ids;
7880       for (auto &dialog : dialogs_) {
7881         Dialog *d = dialog.second.get();
7882         if (need_unread_counter(d->order) && d->notification_settings.use_default_mute_until &&
7883             get_dialog_notification_setting_scope(d->dialog_id) == scope) {
7884           int32 unread_count = d->server_unread_count + d->local_unread_count;
7885           if (unread_count != 0) {
7886             for (auto dialog_list_id : get_dialog_list_ids(d)) {
7887               delta[dialog_list_id] += unread_count;
7888               total_count[dialog_list_id]++;
7889               dialog_list_ids.insert(dialog_list_id);
7890             }
7891           } else if (d->is_marked_as_unread) {
7892             for (auto dialog_list_id : get_dialog_list_ids(d)) {
7893               total_count[dialog_list_id]++;
7894               marked_count[dialog_list_id]++;
7895               dialog_list_ids.insert(dialog_list_id);
7896             }
7897           }
7898         }
7899       }
7900       for (auto dialog_list_id : dialog_list_ids) {
7901         auto *list = get_dialog_list(dialog_list_id);
7902         CHECK(list != nullptr);
7903         if (delta[dialog_list_id] != 0 && list->is_message_unread_count_inited_) {
7904           if (was_muted) {
7905             list->unread_message_muted_count_ -= delta[dialog_list_id];
7906           } else {
7907             list->unread_message_muted_count_ += delta[dialog_list_id];
7908           }
7909           send_update_unread_message_count(*list, DialogId(), true, "update_scope_unmute_timeout");
7910         }
7911         if (total_count[dialog_list_id] != 0 && list->is_dialog_unread_count_inited_) {
7912           if (was_muted) {
7913             list->unread_dialog_muted_count_ -= total_count[dialog_list_id];
7914             list->unread_dialog_muted_marked_count_ -= marked_count[dialog_list_id];
7915           } else {
7916             list->unread_dialog_muted_count_ += total_count[dialog_list_id];
7917             list->unread_dialog_muted_marked_count_ += marked_count[dialog_list_id];
7918           }
7919           send_update_unread_chat_count(*list, DialogId(), true, "update_scope_unmute_timeout");
7920         }
7921       }
7922     }
7923   }
7924 
7925   old_mute_until = new_mute_until;
7926 
7927   if (was_muted != is_muted && !dialog_filters_.empty()) {
7928     for (auto &dialog : dialogs_) {
7929       Dialog *d = dialog.second.get();
7930       if (d->order != DEFAULT_ORDER && d->notification_settings.use_default_mute_until &&
7931           get_dialog_notification_setting_scope(d->dialog_id) == scope) {
7932         update_dialog_lists(d, get_dialog_positions(d), true, false, "update_scope_unmute_timeout");
7933       }
7934     }
7935   }
7936   if (!was_muted && is_muted) {
7937     for (auto &dialog : dialogs_) {
7938       Dialog *d = dialog.second.get();
7939       if (d->order != DEFAULT_ORDER && d->notification_settings.use_default_mute_until &&
7940           get_dialog_notification_setting_scope(d->dialog_id) == scope) {
7941         remove_all_dialog_notifications(d, false, "update_scope_unmute_timeout");
7942       }
7943     }
7944   }
7945 }
7946 
on_dialog_unmute(DialogId dialog_id)7947 void MessagesManager::on_dialog_unmute(DialogId dialog_id) {
7948   if (td_->auth_manager_->is_bot()) {
7949     // just in case
7950     return;
7951   }
7952 
7953   auto d = get_dialog(dialog_id);
7954   CHECK(d != nullptr);
7955 
7956   if (d->notification_settings.use_default_mute_until) {
7957     return;
7958   }
7959   if (d->notification_settings.mute_until == 0) {
7960     return;
7961   }
7962 
7963   auto now = G()->unix_time();
7964   if (d->notification_settings.mute_until > now) {
7965     LOG(ERROR) << "Failed to unmute " << dialog_id << " in " << now << ", will be unmuted in "
7966                << d->notification_settings.mute_until;
7967     schedule_dialog_unmute(dialog_id, false, d->notification_settings.mute_until);
7968     return;
7969   }
7970 
7971   LOG(INFO) << "Unmute " << dialog_id;
7972   update_dialog_unmute_timeout(d, d->notification_settings.use_default_mute_until, d->notification_settings.mute_until,
7973                                false, 0);
7974   send_closure(G()->td(), &Td::send_update,
7975                make_tl_object<td_api::updateChatNotificationSettings>(
7976                    dialog_id.get(), get_chat_notification_settings_object(&d->notification_settings)));
7977   on_dialog_updated(dialog_id, "on_dialog_unmute");
7978 }
7979 
on_scope_unmute(NotificationSettingsScope scope)7980 void MessagesManager::on_scope_unmute(NotificationSettingsScope scope) {
7981   if (td_->auth_manager_->is_bot()) {
7982     // just in case
7983     return;
7984   }
7985 
7986   auto notification_settings = get_scope_notification_settings(scope);
7987   CHECK(notification_settings != nullptr);
7988 
7989   if (notification_settings->mute_until == 0) {
7990     return;
7991   }
7992 
7993   auto now = G()->unix_time();
7994   if (notification_settings->mute_until > now) {
7995     LOG(ERROR) << "Failed to unmute " << scope << " in " << now << ", will be unmuted in "
7996                << notification_settings->mute_until;
7997     schedule_scope_unmute(scope, notification_settings->mute_until);
7998     return;
7999   }
8000 
8001   LOG(INFO) << "Unmute " << scope;
8002   update_scope_unmute_timeout(scope, notification_settings->mute_until, 0);
8003   send_closure(G()->td(), &Td::send_update, get_update_scope_notification_settings_object(scope));
8004   save_scope_notification_settings(scope, *notification_settings);
8005 }
8006 
on_update_dialog_notify_settings(DialogId dialog_id,tl_object_ptr<telegram_api::peerNotifySettings> && peer_notify_settings,const char * source)8007 void MessagesManager::on_update_dialog_notify_settings(
8008     DialogId dialog_id, tl_object_ptr<telegram_api::peerNotifySettings> &&peer_notify_settings, const char *source) {
8009   if (td_->auth_manager_->is_bot()) {
8010     return;
8011   }
8012 
8013   VLOG(notifications) << "Receive notification settings for " << dialog_id << " from " << source << ": "
8014                       << to_string(peer_notify_settings);
8015 
8016   DialogNotificationSettings *current_settings = get_dialog_notification_settings(dialog_id, true);
8017   if (current_settings == nullptr) {
8018     return;
8019   }
8020 
8021   const DialogNotificationSettings notification_settings = ::td::get_dialog_notification_settings(
8022       std::move(peer_notify_settings), current_settings->use_default_disable_pinned_message_notifications,
8023       current_settings->disable_pinned_message_notifications,
8024       current_settings->use_default_disable_mention_notifications, current_settings->disable_mention_notifications);
8025   if (!notification_settings.is_synchronized) {
8026     return;
8027   }
8028 
8029   update_dialog_notification_settings(dialog_id, current_settings, notification_settings);
8030 }
8031 
on_update_scope_notify_settings(NotificationSettingsScope scope,tl_object_ptr<telegram_api::peerNotifySettings> && peer_notify_settings)8032 void MessagesManager::on_update_scope_notify_settings(
8033     NotificationSettingsScope scope, tl_object_ptr<telegram_api::peerNotifySettings> &&peer_notify_settings) {
8034   if (td_->auth_manager_->is_bot()) {
8035     return;
8036   }
8037 
8038   auto old_notification_settings = get_scope_notification_settings(scope);
8039   CHECK(old_notification_settings != nullptr);
8040 
8041   const ScopeNotificationSettings notification_settings = ::td::get_scope_notification_settings(
8042       std::move(peer_notify_settings), old_notification_settings->disable_pinned_message_notifications,
8043       old_notification_settings->disable_mention_notifications);
8044   if (!notification_settings.is_synchronized) {
8045     return;
8046   }
8047 
8048   update_scope_notification_settings(scope, old_notification_settings, notification_settings);
8049 }
8050 
update_dialog_silent_send_message(Dialog * d,bool silent_send_message)8051 bool MessagesManager::update_dialog_silent_send_message(Dialog *d, bool silent_send_message) {
8052   if (td_->auth_manager_->is_bot()) {
8053     // just in case
8054     return false;
8055   }
8056 
8057   CHECK(d != nullptr);
8058   LOG_IF(WARNING, !d->notification_settings.is_synchronized)
8059       << "Have unknown notification settings in " << d->dialog_id;
8060   if (d->notification_settings.silent_send_message == silent_send_message) {
8061     return false;
8062   }
8063 
8064   LOG(INFO) << "Update silent send message in " << d->dialog_id << " to " << silent_send_message;
8065   d->notification_settings.silent_send_message = silent_send_message;
8066 
8067   on_dialog_updated(d->dialog_id, "update_dialog_silent_send_message");
8068 
8069   send_closure(G()->td(), &Td::send_update,
8070                make_tl_object<td_api::updateChatDefaultDisableNotification>(d->dialog_id.get(), silent_send_message));
8071   return true;
8072 }
8073 
reget_dialog_action_bar(DialogId dialog_id,const char * source,bool is_repair)8074 void MessagesManager::reget_dialog_action_bar(DialogId dialog_id, const char *source, bool is_repair) {
8075   if (G()->close_flag() || !dialog_id.is_valid() || td_->auth_manager_->is_bot()) {
8076     return;
8077   }
8078 
8079   Dialog *d = get_dialog_force(dialog_id, source);
8080   if (d == nullptr) {
8081     return;
8082   }
8083 
8084   if (is_repair && !d->need_repair_action_bar) {
8085     d->need_repair_action_bar = true;
8086     on_dialog_updated(dialog_id, source);
8087   }
8088 
8089   LOG(INFO) << "Reget action bar in " << dialog_id << " from " << source;
8090   switch (dialog_id.get_type()) {
8091     case DialogType::User:
8092       td_->contacts_manager_->reload_user_full(dialog_id.get_user_id());
8093       return;
8094     case DialogType::Chat:
8095     case DialogType::Channel:
8096       if (!have_input_peer(dialog_id, AccessRights::Read)) {
8097         return;
8098       }
8099 
8100       return td_->create_handler<GetPeerSettingsQuery>()->send(dialog_id);
8101     case DialogType::SecretChat:
8102     case DialogType::None:
8103     default:
8104       UNREACHABLE();
8105   }
8106 }
8107 
repair_dialog_action_bar(Dialog * d,const char * source)8108 void MessagesManager::repair_dialog_action_bar(Dialog *d, const char *source) {
8109   CHECK(d != nullptr);
8110   auto dialog_id = d->dialog_id;
8111   d->need_repair_action_bar = true;
8112   if (have_input_peer(dialog_id, AccessRights::Read)) {
8113     create_actor<SleepActor>(
8114         "RepairChatActionBarActor", 1.0,
8115         PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, source](Result<Unit> result) {
8116           send_closure(actor_id, &MessagesManager::reget_dialog_action_bar, dialog_id, source, true);
8117         }))
8118         .release();
8119   }
8120   // there is no need to change action bar
8121   on_dialog_updated(dialog_id, source);
8122 }
8123 
hide_dialog_action_bar(DialogId dialog_id)8124 void MessagesManager::hide_dialog_action_bar(DialogId dialog_id) {
8125   Dialog *d = get_dialog_force(dialog_id, "hide_dialog_action_bar");
8126   if (d == nullptr) {
8127     return;
8128   }
8129   hide_dialog_action_bar(d);
8130 }
8131 
hide_dialog_action_bar(Dialog * d)8132 void MessagesManager::hide_dialog_action_bar(Dialog *d) {
8133   CHECK(d->dialog_id.get_type() != DialogType::SecretChat);
8134   if (!d->know_action_bar) {
8135     return;
8136   }
8137   if (d->need_repair_action_bar) {
8138     d->need_repair_action_bar = false;
8139     on_dialog_updated(d->dialog_id, "hide_dialog_action_bar");
8140   }
8141   if (d->action_bar == nullptr) {
8142     return;
8143   }
8144 
8145   d->action_bar = nullptr;
8146   send_update_chat_action_bar(d);
8147 }
8148 
remove_dialog_action_bar(DialogId dialog_id,Promise<Unit> && promise)8149 void MessagesManager::remove_dialog_action_bar(DialogId dialog_id, Promise<Unit> &&promise) {
8150   Dialog *d = get_dialog_force(dialog_id, "remove_dialog_action_bar");
8151   if (d == nullptr) {
8152     return promise.set_error(Status::Error(400, "Chat not found"));
8153   }
8154 
8155   if (!have_input_peer(dialog_id, AccessRights::Read)) {
8156     return promise.set_error(Status::Error(400, "Can't access the chat"));
8157   }
8158 
8159   if (dialog_id.get_type() == DialogType::SecretChat) {
8160     dialog_id = DialogId(td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()));
8161     d = get_dialog_force(dialog_id, "remove_dialog_action_bar 2");
8162     if (d == nullptr) {
8163       return promise.set_error(Status::Error(400, "Chat with the user not found"));
8164     }
8165     if (!have_input_peer(dialog_id, AccessRights::Read)) {
8166       return promise.set_error(Status::Error(400, "Can't access the chat"));
8167     }
8168   }
8169 
8170   if (!d->know_action_bar) {
8171     return promise.set_error(Status::Error(400, "Can't update chat action bar"));
8172   }
8173   if (d->need_repair_action_bar) {
8174     d->need_repair_action_bar = false;
8175     on_dialog_updated(dialog_id, "remove_dialog_action_bar");
8176   }
8177   if (d->action_bar == nullptr) {
8178     return promise.set_value(Unit());
8179   }
8180 
8181   d->action_bar = nullptr;
8182   send_update_chat_action_bar(d);
8183 
8184   toggle_dialog_report_spam_state_on_server(dialog_id, false, 0, std::move(promise));
8185 }
8186 
repair_dialog_active_group_call_id(DialogId dialog_id)8187 void MessagesManager::repair_dialog_active_group_call_id(DialogId dialog_id) {
8188   if (have_input_peer(dialog_id, AccessRights::Read)) {
8189     LOG(INFO) << "Repair active voice chat ID in " << dialog_id;
8190     create_actor<SleepActor>("RepairChatActiveVoiceChatId", 1.0,
8191                              PromiseCreator::lambda([actor_id = actor_id(this), dialog_id](Result<Unit> result) {
8192                                send_closure(actor_id, &MessagesManager::do_repair_dialog_active_group_call_id,
8193                                             dialog_id);
8194                              }))
8195         .release();
8196   }
8197 }
8198 
do_repair_dialog_active_group_call_id(DialogId dialog_id)8199 void MessagesManager::do_repair_dialog_active_group_call_id(DialogId dialog_id) {
8200   if (G()->close_flag()) {
8201     return;
8202   }
8203 
8204   Dialog *d = get_dialog(dialog_id);
8205   CHECK(d != nullptr);
8206   bool need_repair_active_group_call_id = d->has_active_group_call && !d->active_group_call_id.is_valid();
8207   bool need_repair_expected_group_call_id =
8208       d->has_expected_active_group_call_id && d->active_group_call_id != d->expected_active_group_call_id;
8209   d->has_expected_active_group_call_id = false;
8210   if (!need_repair_active_group_call_id && !need_repair_expected_group_call_id) {
8211     return;
8212   }
8213   if (!have_input_peer(dialog_id, AccessRights::Read)) {
8214     return;
8215   }
8216 
8217   reload_dialog_info_full(dialog_id);
8218 }
8219 
8220 class MessagesManager::ToggleDialogReportSpamStateOnServerLogEvent {
8221  public:
8222   DialogId dialog_id_;
8223   bool is_spam_dialog_;
8224 
8225   template <class StorerT>
store(StorerT & storer) const8226   void store(StorerT &storer) const {
8227     td::store(dialog_id_, storer);
8228     td::store(is_spam_dialog_, storer);
8229   }
8230 
8231   template <class ParserT>
parse(ParserT & parser)8232   void parse(ParserT &parser) {
8233     td::parse(dialog_id_, parser);
8234     td::parse(is_spam_dialog_, parser);
8235   }
8236 };
8237 
save_toggle_dialog_report_spam_state_on_server_log_event(DialogId dialog_id,bool is_spam_dialog)8238 uint64 MessagesManager::save_toggle_dialog_report_spam_state_on_server_log_event(DialogId dialog_id,
8239                                                                                  bool is_spam_dialog) {
8240   ToggleDialogReportSpamStateOnServerLogEvent log_event{dialog_id, is_spam_dialog};
8241   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::ToggleDialogReportSpamStateOnServer,
8242                     get_log_event_storer(log_event));
8243 }
8244 
toggle_dialog_report_spam_state_on_server(DialogId dialog_id,bool is_spam_dialog,uint64 log_event_id,Promise<Unit> && promise)8245 void MessagesManager::toggle_dialog_report_spam_state_on_server(DialogId dialog_id, bool is_spam_dialog,
8246                                                                 uint64 log_event_id, Promise<Unit> &&promise) {
8247   if (log_event_id == 0 && G()->parameters().use_message_db) {
8248     log_event_id = save_toggle_dialog_report_spam_state_on_server_log_event(dialog_id, is_spam_dialog);
8249   }
8250 
8251   auto new_promise = get_erase_log_event_promise(log_event_id, std::move(promise));
8252   promise = std::move(new_promise);  // to prevent self-move
8253 
8254   switch (dialog_id.get_type()) {
8255     case DialogType::User:
8256     case DialogType::Chat:
8257     case DialogType::Channel:
8258       return td_->create_handler<UpdatePeerSettingsQuery>(std::move(promise))->send(dialog_id, is_spam_dialog);
8259     case DialogType::SecretChat:
8260       if (is_spam_dialog) {
8261         return td_->create_handler<ReportEncryptedSpamQuery>(std::move(promise))->send(dialog_id);
8262       } else {
8263         auto user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id());
8264         if (!user_id.is_valid()) {
8265           return promise.set_error(Status::Error(400, "Peer user not found"));
8266         }
8267         return td_->create_handler<UpdatePeerSettingsQuery>(std::move(promise))->send(DialogId(user_id), false);
8268       }
8269     case DialogType::None:
8270     default:
8271       UNREACHABLE();
8272       return;
8273   }
8274 }
8275 
can_report_dialog(DialogId dialog_id) const8276 bool MessagesManager::can_report_dialog(DialogId dialog_id) const {
8277   // doesn't include possibility of report from action bar
8278   switch (dialog_id.get_type()) {
8279     case DialogType::User:
8280       return td_->contacts_manager_->can_report_user(dialog_id.get_user_id());
8281     case DialogType::Chat:
8282       return false;
8283     case DialogType::Channel:
8284       return !td_->contacts_manager_->get_channel_status(dialog_id.get_channel_id()).is_creator();
8285     case DialogType::SecretChat:
8286       return false;
8287     case DialogType::None:
8288     default:
8289       UNREACHABLE();
8290       return false;
8291   }
8292 }
8293 
report_dialog(DialogId dialog_id,const vector<MessageId> & message_ids,ReportReason && reason,Promise<Unit> && promise)8294 void MessagesManager::report_dialog(DialogId dialog_id, const vector<MessageId> &message_ids, ReportReason &&reason,
8295                                     Promise<Unit> &&promise) {
8296   Dialog *d = get_dialog_force(dialog_id, "report_dialog");
8297   if (d == nullptr) {
8298     return promise.set_error(Status::Error(400, "Chat not found"));
8299   }
8300 
8301   if (!have_input_peer(dialog_id, AccessRights::Read)) {
8302     return promise.set_error(Status::Error(400, "Can't access the chat"));
8303   }
8304 
8305   Dialog *user_d = d;
8306   bool is_dialog_spam_report = false;
8307   bool can_report_spam = false;
8308   if (reason.is_spam() && message_ids.empty()) {
8309     // report from action bar
8310     if (dialog_id.get_type() == DialogType::SecretChat) {
8311       auto user_dialog_id = DialogId(td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()));
8312       user_d = get_dialog_force(user_dialog_id, "report_dialog 2");
8313       if (user_d == nullptr) {
8314         return promise.set_error(Status::Error(400, "Chat with the user not found"));
8315       }
8316     }
8317     is_dialog_spam_report = user_d->know_action_bar;
8318     can_report_spam = user_d->action_bar != nullptr && user_d->action_bar->can_report_spam();
8319   }
8320 
8321   if (is_dialog_spam_report && can_report_spam) {
8322     hide_dialog_action_bar(user_d);
8323     return toggle_dialog_report_spam_state_on_server(dialog_id, true, 0, std::move(promise));
8324   }
8325 
8326   if (!can_report_dialog(dialog_id)) {
8327     if (is_dialog_spam_report) {
8328       return promise.set_value(Unit());
8329     }
8330 
8331     return promise.set_error(Status::Error(400, "Chat can't be reported"));
8332   }
8333 
8334   vector<MessageId> server_message_ids;
8335   for (auto message_id : message_ids) {
8336     if (message_id.is_scheduled()) {
8337       return promise.set_error(Status::Error(400, "Can't report scheduled messages"));
8338     }
8339     if (message_id.is_valid() && message_id.is_server()) {
8340       server_message_ids.push_back(message_id);
8341     }
8342   }
8343 
8344   if (dialog_id.get_type() == DialogType::Channel && reason.is_unrelated_location()) {
8345     hide_dialog_action_bar(d);
8346   }
8347 
8348   td_->create_handler<ReportPeerQuery>(std::move(promise))->send(dialog_id, server_message_ids, std::move(reason));
8349 }
8350 
report_dialog_photo(DialogId dialog_id,FileId file_id,ReportReason && reason,Promise<Unit> && promise)8351 void MessagesManager::report_dialog_photo(DialogId dialog_id, FileId file_id, ReportReason &&reason,
8352                                           Promise<Unit> &&promise) {
8353   Dialog *d = get_dialog_force(dialog_id, "report_dialog_photo");
8354   if (d == nullptr) {
8355     return promise.set_error(Status::Error(400, "Chat not found"));
8356   }
8357 
8358   if (!have_input_peer(dialog_id, AccessRights::Read)) {
8359     return promise.set_error(Status::Error(400, "Can't access the chat"));
8360   }
8361 
8362   if (!can_report_dialog(dialog_id)) {
8363     return promise.set_error(Status::Error(400, "Chat photo can't be reported"));
8364   }
8365 
8366   auto file_view = td_->file_manager_->get_file_view(file_id);
8367   if (file_view.empty()) {
8368     return promise.set_error(Status::Error(400, "Unknown file ID"));
8369   }
8370   if (file_view.get_type() != FileType::Photo || !file_view.has_remote_location() ||
8371       !file_view.remote_location().is_photo()) {
8372     return promise.set_error(Status::Error(400, "Only full chat photos can be reported"));
8373   }
8374 
8375   td_->create_handler<ReportProfilePhotoQuery>(std::move(promise))
8376       ->send(dialog_id, file_id, file_view.remote_location().as_input_photo(), std::move(reason));
8377 }
8378 
on_get_peer_settings(DialogId dialog_id,tl_object_ptr<telegram_api::peerSettings> && peer_settings,bool ignore_privacy_exception)8379 void MessagesManager::on_get_peer_settings(DialogId dialog_id,
8380                                            tl_object_ptr<telegram_api::peerSettings> &&peer_settings,
8381                                            bool ignore_privacy_exception) {
8382   CHECK(peer_settings != nullptr);
8383   if (td_->auth_manager_->is_bot()) {
8384     return;
8385   }
8386 
8387   if (dialog_id.get_type() == DialogType::User && !ignore_privacy_exception) {
8388     td_->contacts_manager_->on_update_user_need_phone_number_privacy_exception(dialog_id.get_user_id(),
8389                                                                                peer_settings->need_contacts_exception_);
8390   }
8391 
8392   Dialog *d = get_dialog_force(dialog_id, "on_get_peer_settings");
8393   if (d == nullptr) {
8394     return;
8395   }
8396 
8397   auto distance =
8398       (peer_settings->flags_ & telegram_api::peerSettings::GEO_DISTANCE_MASK) != 0 ? peer_settings->geo_distance_ : -1;
8399   if (distance < -1 || d->has_outgoing_messages) {
8400     distance = -1;
8401   }
8402   auto action_bar =
8403       DialogActionBar::create(peer_settings->report_spam_, peer_settings->add_contact_, peer_settings->block_contact_,
8404                               peer_settings->share_contact_, peer_settings->report_geo_, peer_settings->autoarchived_,
8405                               distance, peer_settings->invite_members_, peer_settings->request_chat_title_,
8406                               peer_settings->request_chat_broadcast_, peer_settings->request_chat_date_);
8407 
8408   fix_dialog_action_bar(d, action_bar.get());
8409 
8410   if (d->action_bar == action_bar) {
8411     if (!d->know_action_bar || d->need_repair_action_bar) {
8412       d->know_action_bar = true;
8413       d->need_repair_action_bar = false;
8414       on_dialog_updated(d->dialog_id, "on_get_peer_settings");
8415     }
8416     return;
8417   }
8418 
8419   d->know_action_bar = true;
8420   d->need_repair_action_bar = false;
8421   d->action_bar = std::move(action_bar);
8422 
8423   send_update_chat_action_bar(d);
8424 }
8425 
fix_dialog_action_bar(const Dialog * d,DialogActionBar * action_bar)8426 void MessagesManager::fix_dialog_action_bar(const Dialog *d, DialogActionBar *action_bar) {
8427   if (action_bar == nullptr) {
8428     return;
8429   }
8430 
8431   CHECK(d != nullptr);
8432   action_bar->fix(td_, d->dialog_id, d->is_blocked, d->folder_id);
8433 }
8434 
get_login_button_url(FullMessageId full_message_id,int64 button_id)8435 Result<string> MessagesManager::get_login_button_url(FullMessageId full_message_id, int64 button_id) {
8436   Dialog *d = get_dialog_force(full_message_id.get_dialog_id(), "get_login_button_url");
8437   if (d == nullptr) {
8438     return Status::Error(400, "Chat not found");
8439   }
8440   if (!have_input_peer(d->dialog_id, AccessRights::Read)) {
8441     return Status::Error(400, "Can't access the chat");
8442   }
8443 
8444   auto m = get_message_force(d, full_message_id.get_message_id(), "get_login_button_url");
8445   if (m == nullptr) {
8446     return Status::Error(400, "Message not found");
8447   }
8448   if (m->reply_markup == nullptr || m->reply_markup->type != ReplyMarkup::Type::InlineKeyboard) {
8449     return Status::Error(400, "Message has no inline keyboard");
8450   }
8451   if (m->message_id.is_scheduled()) {
8452     return Status::Error(400, "Can't use login buttons from scheduled messages");
8453   }
8454   if (!m->message_id.is_server()) {
8455     // it shouldn't have UrlAuth buttons anyway
8456     return Status::Error(400, "Message is not server");
8457   }
8458   if (d->dialog_id.get_type() == DialogType::SecretChat) {
8459     // secret chat messages can't have reply markup, so this shouldn't happen now
8460     return Status::Error(400, "Message is in a secret chat");
8461   }
8462   if (button_id < std::numeric_limits<int32>::min() || button_id > std::numeric_limits<int32>::max()) {
8463     return Status::Error(400, "Invalid button identifier specified");
8464   }
8465 
8466   for (auto &row : m->reply_markup->inline_keyboard) {
8467     for (auto &button : row) {
8468       if (button.type == InlineKeyboardButton::Type::UrlAuth && button.id == button_id) {
8469         return button.data;
8470       }
8471     }
8472   }
8473 
8474   return Status::Error(400, "Button not found");
8475 }
8476 
load_secret_thumbnail(FileId thumbnail_file_id)8477 void MessagesManager::load_secret_thumbnail(FileId thumbnail_file_id) {
8478   class Callback final : public FileManager::DownloadCallback {
8479    public:
8480     explicit Callback(Promise<> download_promise) : download_promise_(std::move(download_promise)) {
8481     }
8482 
8483     void on_download_ok(FileId file_id) final {
8484       download_promise_.set_value(Unit());
8485     }
8486     void on_download_error(FileId file_id, Status error) final {
8487       download_promise_.set_error(std::move(error));
8488     }
8489 
8490    private:
8491     Promise<> download_promise_;
8492   };
8493 
8494   auto thumbnail_promise = PromiseCreator::lambda([actor_id = actor_id(this),
8495                                                    thumbnail_file_id](Result<BufferSlice> r_thumbnail) {
8496     BufferSlice thumbnail_slice;
8497     if (r_thumbnail.is_ok()) {
8498       thumbnail_slice = r_thumbnail.move_as_ok();
8499     }
8500     send_closure(actor_id, &MessagesManager::on_load_secret_thumbnail, thumbnail_file_id, std::move(thumbnail_slice));
8501   });
8502 
8503   auto download_promise = PromiseCreator::lambda(
8504       [thumbnail_file_id, thumbnail_promise = std::move(thumbnail_promise)](Result<Unit> r_download) mutable {
8505         if (r_download.is_error()) {
8506           thumbnail_promise.set_error(r_download.move_as_error());
8507           return;
8508         }
8509         send_closure(G()->file_manager(), &FileManager::get_content, thumbnail_file_id, std::move(thumbnail_promise));
8510       });
8511 
8512   send_closure(G()->file_manager(), &FileManager::download, thumbnail_file_id,
8513                std::make_shared<Callback>(std::move(download_promise)), 1, -1, -1);
8514 }
8515 
on_upload_media(FileId file_id,tl_object_ptr<telegram_api::InputFile> input_file,tl_object_ptr<telegram_api::InputEncryptedFile> input_encrypted_file)8516 void MessagesManager::on_upload_media(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file,
8517                                       tl_object_ptr<telegram_api::InputEncryptedFile> input_encrypted_file) {
8518   LOG(INFO) << "File " << file_id << " has been uploaded";
8519 
8520   auto it = being_uploaded_files_.find(file_id);
8521   if (it == being_uploaded_files_.end()) {
8522     // callback may be called just before the file upload was canceled
8523     return;
8524   }
8525 
8526   auto full_message_id = it->second.first;
8527   auto thumbnail_file_id = it->second.second;
8528 
8529   being_uploaded_files_.erase(it);
8530 
8531   Message *m = get_message(full_message_id);
8532   if (m == nullptr) {
8533     // message has already been deleted by the user or sent to inaccessible channel, do not need to send or edit it
8534     // file upload should be already canceled in cancel_send_message_query, it shouldn't happen
8535     LOG(ERROR) << "Message with a media has already been deleted";
8536     return;
8537   }
8538 
8539   bool is_edit = m->message_id.is_any_server();
8540   auto dialog_id = full_message_id.get_dialog_id();
8541   auto can_send_status = can_send_message(dialog_id);
8542   if (!is_edit && can_send_status.is_error()) {
8543     // user has left the chat during upload of the file or lost their privileges
8544     LOG(INFO) << "Can't send a message to " << dialog_id << ": " << can_send_status.error();
8545 
8546     fail_send_message(full_message_id, can_send_status.move_as_error());
8547     return;
8548   }
8549 
8550   switch (dialog_id.get_type()) {
8551     case DialogType::User:
8552     case DialogType::Chat:
8553     case DialogType::Channel:
8554       if (input_file && thumbnail_file_id.is_valid()) {
8555         // TODO: download thumbnail if needed (like in secret chats)
8556         LOG(INFO) << "Ask to upload thumbnail " << thumbnail_file_id;
8557         CHECK(being_uploaded_thumbnails_.find(thumbnail_file_id) == being_uploaded_thumbnails_.end());
8558         being_uploaded_thumbnails_[thumbnail_file_id] = {full_message_id, file_id, std::move(input_file)};
8559         td_->file_manager_->upload(thumbnail_file_id, upload_thumbnail_callback_, 32, m->message_id.get());
8560       } else {
8561         do_send_media(dialog_id, m, file_id, thumbnail_file_id, std::move(input_file), nullptr);
8562       }
8563       break;
8564     case DialogType::SecretChat:
8565       if (thumbnail_file_id.is_valid()) {
8566         LOG(INFO) << "Ask to load thumbnail " << thumbnail_file_id;
8567         CHECK(being_loaded_secret_thumbnails_.find(thumbnail_file_id) == being_loaded_secret_thumbnails_.end());
8568         being_loaded_secret_thumbnails_[thumbnail_file_id] = {full_message_id, file_id,
8569                                                               std::move(input_encrypted_file)};
8570 
8571         load_secret_thumbnail(thumbnail_file_id);
8572       } else {
8573         do_send_secret_media(dialog_id, m, file_id, thumbnail_file_id, std::move(input_encrypted_file), BufferSlice());
8574       }
8575       break;
8576     case DialogType::None:
8577     default:
8578       UNREACHABLE();
8579       break;
8580   }
8581 }
8582 
do_send_media(DialogId dialog_id,Message * m,FileId file_id,FileId thumbnail_file_id,tl_object_ptr<telegram_api::InputFile> input_file,tl_object_ptr<telegram_api::InputFile> input_thumbnail)8583 void MessagesManager::do_send_media(DialogId dialog_id, Message *m, FileId file_id, FileId thumbnail_file_id,
8584                                     tl_object_ptr<telegram_api::InputFile> input_file,
8585                                     tl_object_ptr<telegram_api::InputFile> input_thumbnail) {
8586   CHECK(m != nullptr);
8587 
8588   bool have_input_file = input_file != nullptr;
8589   bool have_input_thumbnail = input_thumbnail != nullptr;
8590   LOG(INFO) << "Do send media file " << file_id << " with thumbnail " << thumbnail_file_id
8591             << ", have_input_file = " << have_input_file << ", have_input_thumbnail = " << have_input_thumbnail
8592             << ", TTL = " << m->ttl;
8593 
8594   MessageContent *content = nullptr;
8595   if (m->message_id.is_any_server()) {
8596     content = m->edited_content.get();
8597     if (content == nullptr) {
8598       LOG(ERROR) << "Message has no edited content";
8599       return;
8600     }
8601   } else {
8602     content = m->content.get();
8603   }
8604 
8605   auto input_media = get_input_media(content, td_, std::move(input_file), std::move(input_thumbnail), file_id,
8606                                      thumbnail_file_id, m->ttl, true);
8607   LOG_CHECK(input_media != nullptr) << to_string(get_message_object(dialog_id, m, "do_send_media")) << ' '
8608                                     << have_input_file << ' ' << have_input_thumbnail << ' ' << file_id << ' '
8609                                     << thumbnail_file_id << ' ' << m->ttl;
8610 
8611   on_message_media_uploaded(dialog_id, m, std::move(input_media), file_id, thumbnail_file_id);
8612 }
8613 
do_send_secret_media(DialogId dialog_id,Message * m,FileId file_id,FileId thumbnail_file_id,tl_object_ptr<telegram_api::InputEncryptedFile> input_encrypted_file,BufferSlice thumbnail)8614 void MessagesManager::do_send_secret_media(DialogId dialog_id, Message *m, FileId file_id, FileId thumbnail_file_id,
8615                                            tl_object_ptr<telegram_api::InputEncryptedFile> input_encrypted_file,
8616                                            BufferSlice thumbnail) {
8617   CHECK(dialog_id.get_type() == DialogType::SecretChat);
8618   CHECK(m != nullptr);
8619   CHECK(m->message_id.is_valid());
8620   CHECK(m->message_id.is_yet_unsent());
8621 
8622   bool have_input_file = input_encrypted_file != nullptr;
8623   LOG(INFO) << "Do send secret media file " << file_id << " with thumbnail " << thumbnail_file_id
8624             << ", have_input_file = " << have_input_file;
8625 
8626   on_secret_message_media_uploaded(
8627       dialog_id, m,
8628       get_secret_input_media(m->content.get(), td_, std::move(input_encrypted_file), std::move(thumbnail)), file_id,
8629       thumbnail_file_id);
8630 }
8631 
on_upload_media_error(FileId file_id,Status status)8632 void MessagesManager::on_upload_media_error(FileId file_id, Status status) {
8633   if (G()->close_flag()) {
8634     // do not fail upload if closing
8635     return;
8636   }
8637 
8638   LOG(WARNING) << "File " << file_id << " has upload error " << status;
8639   CHECK(status.is_error());
8640 
8641   auto it = being_uploaded_files_.find(file_id);
8642   if (it == being_uploaded_files_.end()) {
8643     // callback may be called just before the file upload was canceled
8644     return;
8645   }
8646 
8647   auto full_message_id = it->second.first;
8648 
8649   being_uploaded_files_.erase(it);
8650 
8651   bool is_edit = full_message_id.get_message_id().is_any_server();
8652   if (is_edit) {
8653     fail_edit_message_media(full_message_id, Status::Error(status.code() > 0 ? status.code() : 500, status.message()));
8654   } else {
8655     fail_send_message(full_message_id, std::move(status));
8656   }
8657 }
8658 
on_load_secret_thumbnail(FileId thumbnail_file_id,BufferSlice thumbnail)8659 void MessagesManager::on_load_secret_thumbnail(FileId thumbnail_file_id, BufferSlice thumbnail) {
8660   if (G()->close_flag()) {
8661     // do not send secret media if closing, thumbnail may be wrong
8662     return;
8663   }
8664 
8665   LOG(INFO) << "SecretThumbnail " << thumbnail_file_id << " has been loaded with size " << thumbnail.size();
8666 
8667   auto it = being_loaded_secret_thumbnails_.find(thumbnail_file_id);
8668   if (it == being_loaded_secret_thumbnails_.end()) {
8669     // just in case, as in on_upload_thumbnail
8670     return;
8671   }
8672 
8673   auto full_message_id = it->second.full_message_id;
8674   auto file_id = it->second.file_id;
8675   auto input_file = std::move(it->second.input_file);
8676 
8677   being_loaded_secret_thumbnails_.erase(it);
8678 
8679   Message *m = get_message(full_message_id);
8680   if (m == nullptr) {
8681     // message has already been deleted by the user, do not need to send it
8682     // cancel file upload of the main file to allow next upload with the same file to succeed
8683     LOG(INFO) << "Message with a media has already been deleted";
8684     cancel_upload_file(file_id);
8685     return;
8686   }
8687   CHECK(m->message_id.is_yet_unsent());
8688 
8689   if (thumbnail.empty()) {
8690     delete_message_content_thumbnail(m->content.get(), td_);
8691   }
8692 
8693   auto dialog_id = full_message_id.get_dialog_id();
8694   auto can_send_status = can_send_message(dialog_id);
8695   if (can_send_status.is_error()) {
8696     // secret chat was closed during load of the file
8697     LOG(INFO) << "Can't send a message to " << dialog_id << ": " << can_send_status.error();
8698 
8699     fail_send_message(full_message_id, can_send_status.move_as_error());
8700     return;
8701   }
8702 
8703   do_send_secret_media(dialog_id, m, file_id, thumbnail_file_id, std::move(input_file), std::move(thumbnail));
8704 }
8705 
on_upload_thumbnail(FileId thumbnail_file_id,tl_object_ptr<telegram_api::InputFile> thumbnail_input_file)8706 void MessagesManager::on_upload_thumbnail(FileId thumbnail_file_id,
8707                                           tl_object_ptr<telegram_api::InputFile> thumbnail_input_file) {
8708   if (G()->close_flag()) {
8709     // do not fail upload if closing
8710     return;
8711   }
8712 
8713   LOG(INFO) << "Thumbnail " << thumbnail_file_id << " has been uploaded as " << to_string(thumbnail_input_file);
8714 
8715   auto it = being_uploaded_thumbnails_.find(thumbnail_file_id);
8716   if (it == being_uploaded_thumbnails_.end()) {
8717     // callback may be called just before the thumbnail upload was canceled
8718     return;
8719   }
8720 
8721   auto full_message_id = it->second.full_message_id;
8722   auto file_id = it->second.file_id;
8723   auto input_file = std::move(it->second.input_file);
8724 
8725   being_uploaded_thumbnails_.erase(it);
8726 
8727   Message *m = get_message(full_message_id);
8728   if (m == nullptr) {
8729     // message has already been deleted by the user or sent to inaccessible channel, do not need to send or edit it
8730     // thumbnail file upload should be already canceled in cancel_send_message_query
8731     LOG(ERROR) << "Message with a media has already been deleted";
8732     return;
8733   }
8734 
8735   bool is_edit = m->message_id.is_any_server();
8736 
8737   if (thumbnail_input_file == nullptr) {
8738     delete_message_content_thumbnail(is_edit ? m->edited_content.get() : m->content.get(), td_);
8739   }
8740 
8741   auto dialog_id = full_message_id.get_dialog_id();
8742   auto can_send_status = can_send_message(dialog_id);
8743   if (!is_edit && can_send_status.is_error()) {
8744     // user has left the chat during upload of the thumbnail or lost their privileges
8745     LOG(INFO) << "Can't send a message to " << dialog_id << ": " << can_send_status.error();
8746 
8747     fail_send_message(full_message_id, can_send_status.move_as_error());
8748     return;
8749   }
8750 
8751   do_send_media(dialog_id, m, file_id, thumbnail_file_id, std::move(input_file), std::move(thumbnail_input_file));
8752 }
8753 
on_upload_dialog_photo(FileId file_id,tl_object_ptr<telegram_api::InputFile> input_file)8754 void MessagesManager::on_upload_dialog_photo(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) {
8755   LOG(INFO) << "File " << file_id << " has been uploaded";
8756 
8757   auto it = being_uploaded_dialog_photos_.find(file_id);
8758   if (it == being_uploaded_dialog_photos_.end()) {
8759     // just in case, as in on_upload_media
8760     return;
8761   }
8762 
8763   DialogId dialog_id = it->second.dialog_id;
8764   double main_frame_timestamp = it->second.main_frame_timestamp;
8765   bool is_animation = it->second.is_animation;
8766   bool is_reupload = it->second.is_reupload;
8767   Promise<Unit> promise = std::move(it->second.promise);
8768 
8769   being_uploaded_dialog_photos_.erase(it);
8770 
8771   FileView file_view = td_->file_manager_->get_file_view(file_id);
8772   CHECK(!file_view.is_encrypted());
8773   if (input_file == nullptr && file_view.has_remote_location()) {
8774     if (file_view.main_remote_location().is_web()) {
8775       return promise.set_error(Status::Error(400, "Can't use web photo as profile photo"));
8776     }
8777     if (is_reupload) {
8778       return promise.set_error(Status::Error(400, "Failed to reupload the file"));
8779     }
8780 
8781     if (is_animation) {
8782       CHECK(file_view.get_type() == FileType::Animation);
8783       // delete file reference and forcely reupload the file
8784       auto file_reference = FileManager::extract_file_reference(file_view.main_remote_location().as_input_document());
8785       td_->file_manager_->delete_file_reference(file_id, file_reference);
8786       upload_dialog_photo(dialog_id, file_id, is_animation, main_frame_timestamp, true, std::move(promise), {-1});
8787     } else {
8788       CHECK(file_view.get_type() == FileType::Photo);
8789       auto input_photo = file_view.main_remote_location().as_input_photo();
8790       auto input_chat_photo = make_tl_object<telegram_api::inputChatPhoto>(std::move(input_photo));
8791       send_edit_dialog_photo_query(dialog_id, file_id, std::move(input_chat_photo), std::move(promise));
8792     }
8793     return;
8794   }
8795   CHECK(input_file != nullptr);
8796 
8797   int32 flags = 0;
8798   tl_object_ptr<telegram_api::InputFile> photo_input_file;
8799   tl_object_ptr<telegram_api::InputFile> video_input_file;
8800   if (is_animation) {
8801     flags |= telegram_api::inputChatUploadedPhoto::VIDEO_MASK;
8802     video_input_file = std::move(input_file);
8803 
8804     if (main_frame_timestamp != 0.0) {
8805       flags |= telegram_api::inputChatUploadedPhoto::VIDEO_START_TS_MASK;
8806     }
8807   } else {
8808     flags |= telegram_api::inputChatUploadedPhoto::FILE_MASK;
8809     photo_input_file = std::move(input_file);
8810   }
8811 
8812   auto input_chat_photo = make_tl_object<telegram_api::inputChatUploadedPhoto>(
8813       flags, std::move(photo_input_file), std::move(video_input_file), main_frame_timestamp);
8814   send_edit_dialog_photo_query(dialog_id, file_id, std::move(input_chat_photo), std::move(promise));
8815 }
8816 
on_upload_dialog_photo_error(FileId file_id,Status status)8817 void MessagesManager::on_upload_dialog_photo_error(FileId file_id, Status status) {
8818   if (G()->close_flag()) {
8819     // do not fail upload if closing
8820     return;
8821   }
8822 
8823   LOG(INFO) << "File " << file_id << " has upload error " << status;
8824   CHECK(status.is_error());
8825 
8826   auto it = being_uploaded_dialog_photos_.find(file_id);
8827   if (it == being_uploaded_dialog_photos_.end()) {
8828     // just in case, as in on_upload_media_error
8829     return;
8830   }
8831 
8832   Promise<Unit> promise = std::move(it->second.promise);
8833 
8834   being_uploaded_dialog_photos_.erase(it);
8835 
8836   promise.set_error(std::move(status));
8837 }
8838 
on_upload_imported_messages(FileId file_id,tl_object_ptr<telegram_api::InputFile> input_file)8839 void MessagesManager::on_upload_imported_messages(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) {
8840   LOG(INFO) << "File " << file_id << " has been uploaded";
8841 
8842   auto it = being_uploaded_imported_messages_.find(file_id);
8843   if (it == being_uploaded_imported_messages_.end()) {
8844     // just in case, as in on_upload_media
8845     return;
8846   }
8847 
8848   CHECK(it->second != nullptr);
8849   DialogId dialog_id = it->second->dialog_id;
8850   vector<FileId> attached_file_ids = std::move(it->second->attached_file_ids);
8851   bool is_reupload = it->second->is_reupload;
8852   Promise<Unit> promise = std::move(it->second->promise);
8853 
8854   being_uploaded_imported_messages_.erase(it);
8855 
8856   TRY_STATUS_PROMISE(promise, can_send_message(dialog_id));
8857 
8858   FileView file_view = td_->file_manager_->get_file_view(file_id);
8859   CHECK(!file_view.is_encrypted());
8860   if (input_file == nullptr && file_view.has_remote_location()) {
8861     if (file_view.main_remote_location().is_web()) {
8862       return promise.set_error(Status::Error(400, "Can't use web file"));
8863     }
8864     if (is_reupload) {
8865       return promise.set_error(Status::Error(400, "Failed to reupload the file"));
8866     }
8867 
8868     CHECK(file_view.get_type() == FileType::Document);
8869     // delete file reference and forcely reupload the file
8870     auto file_reference = FileManager::extract_file_reference(file_view.main_remote_location().as_input_document());
8871     td_->file_manager_->delete_file_reference(file_id, file_reference);
8872     upload_imported_messages(dialog_id, file_id, std::move(attached_file_ids), true, std::move(promise), {-1});
8873     return;
8874   }
8875   CHECK(input_file != nullptr);
8876 
8877   td_->create_handler<InitHistoryImportQuery>(std::move(promise))
8878       ->send(dialog_id, file_id, std::move(input_file), std::move(attached_file_ids));
8879 }
8880 
on_upload_imported_messages_error(FileId file_id,Status status)8881 void MessagesManager::on_upload_imported_messages_error(FileId file_id, Status status) {
8882   if (G()->close_flag()) {
8883     // do not fail upload if closing
8884     return;
8885   }
8886 
8887   LOG(INFO) << "File " << file_id << " has upload error " << status;
8888   CHECK(status.is_error());
8889 
8890   auto it = being_uploaded_imported_messages_.find(file_id);
8891   if (it == being_uploaded_imported_messages_.end()) {
8892     // just in case, as in on_upload_media_error
8893     return;
8894   }
8895 
8896   Promise<Unit> promise = std::move(it->second->promise);
8897 
8898   being_uploaded_imported_messages_.erase(it);
8899 
8900   promise.set_error(std::move(status));
8901 }
8902 
on_upload_imported_message_attachment(FileId file_id,tl_object_ptr<telegram_api::InputFile> input_file)8903 void MessagesManager::on_upload_imported_message_attachment(FileId file_id,
8904                                                             tl_object_ptr<telegram_api::InputFile> input_file) {
8905   LOG(INFO) << "File " << file_id << " has been uploaded";
8906 
8907   auto it = being_uploaded_imported_message_attachments_.find(file_id);
8908   if (it == being_uploaded_imported_message_attachments_.end()) {
8909     // just in case, as in on_upload_media
8910     return;
8911   }
8912 
8913   CHECK(it->second != nullptr);
8914   DialogId dialog_id = it->second->dialog_id;
8915   int64 import_id = it->second->import_id;
8916   bool is_reupload = it->second->is_reupload;
8917   Promise<Unit> promise = std::move(it->second->promise);
8918 
8919   being_uploaded_imported_message_attachments_.erase(it);
8920 
8921   FileView file_view = td_->file_manager_->get_file_view(file_id);
8922   CHECK(!file_view.is_encrypted());
8923   if (input_file == nullptr && file_view.has_remote_location()) {
8924     if (file_view.main_remote_location().is_web()) {
8925       return promise.set_error(Status::Error(400, "Can't use web file"));
8926     }
8927     if (is_reupload) {
8928       return promise.set_error(Status::Error(400, "Failed to reupload the file"));
8929     }
8930 
8931     // delete file reference and forcely reupload the file
8932     auto file_reference =
8933         file_view.get_type() == FileType::Photo
8934             ? FileManager::extract_file_reference(file_view.main_remote_location().as_input_photo())
8935             : FileManager::extract_file_reference(file_view.main_remote_location().as_input_document());
8936     td_->file_manager_->delete_file_reference(file_id, file_reference);
8937     upload_imported_message_attachment(dialog_id, import_id, file_id, true, std::move(promise), {-1});
8938     return;
8939   }
8940   CHECK(input_file != nullptr);
8941 
8942   auto suggested_path = file_view.suggested_path();
8943   const PathView path_view(suggested_path);
8944   td_->create_handler<UploadImportedMediaQuery>(std::move(promise))
8945       ->send(dialog_id, import_id, path_view.file_name().str(), file_id,
8946              get_fake_input_media(td_, std::move(input_file), file_id));
8947 }
8948 
on_upload_imported_message_attachment_error(FileId file_id,Status status)8949 void MessagesManager::on_upload_imported_message_attachment_error(FileId file_id, Status status) {
8950   if (G()->close_flag()) {
8951     // do not fail upload if closing
8952     return;
8953   }
8954 
8955   LOG(INFO) << "File " << file_id << " has upload error " << status;
8956   CHECK(status.is_error());
8957 
8958   auto it = being_uploaded_imported_message_attachments_.find(file_id);
8959   if (it == being_uploaded_imported_message_attachments_.end()) {
8960     // just in case, as in on_upload_media_error
8961     return;
8962   }
8963 
8964   Promise<Unit> promise = std::move(it->second->promise);
8965 
8966   being_uploaded_imported_message_attachments_.erase(it);
8967 
8968   promise.set_error(std::move(status));
8969 }
8970 
before_get_difference()8971 void MessagesManager::before_get_difference() {
8972   running_get_difference_ = true;
8973 
8974   // scheduled messages are not returned in getDifference, so we must always reget them after it
8975   scheduled_messages_sync_generation_++;
8976 }
8977 
after_get_difference()8978 void MessagesManager::after_get_difference() {
8979   CHECK(!td_->updates_manager_->running_get_difference());
8980 
8981   running_get_difference_ = false;
8982 
8983   if (!pending_on_get_dialogs_.empty()) {
8984     LOG(INFO) << "Apply postponed results of getDialogs";
8985     for (auto &res : pending_on_get_dialogs_) {
8986       on_get_dialogs(res.folder_id, std::move(res.dialogs), res.total_count, std::move(res.messages),
8987                      std::move(res.promise));
8988     }
8989     pending_on_get_dialogs_.clear();
8990   }
8991 
8992   if (!postponed_chat_read_inbox_updates_.empty()) {
8993     LOG(INFO) << "Send postponed chat read inbox updates";
8994     auto dialog_ids = std::move(postponed_chat_read_inbox_updates_);
8995     for (auto dialog_id : dialog_ids) {
8996       send_update_chat_read_inbox(get_dialog(dialog_id), false, "after_get_difference");
8997     }
8998   }
8999   while (!postponed_unread_message_count_updates_.empty()) {
9000     auto *list = get_dialog_list(*postponed_unread_message_count_updates_.begin());
9001     CHECK(list != nullptr);
9002     send_update_unread_message_count(*list, DialogId(), true, "after_get_difference");
9003   }
9004   while (!postponed_unread_chat_count_updates_.empty()) {
9005     auto *list = get_dialog_list(*postponed_unread_chat_count_updates_.begin());
9006     CHECK(list != nullptr);
9007     send_update_unread_chat_count(*list, DialogId(), true, "after_get_difference");
9008   }
9009 
9010   vector<FullMessageId> update_message_ids_to_delete;
9011   for (auto &it : update_message_ids_) {
9012     // there can be unhandled updateMessageId updates after getDifference even for ordinary chats,
9013     // because despite updates coming during getDifference have already been applied,
9014     // some of them could be postponed because of pts gap
9015     auto full_message_id = it.first;
9016     auto dialog_id = full_message_id.get_dialog_id();
9017     auto message_id = full_message_id.get_message_id();
9018     CHECK(message_id.is_valid());
9019     CHECK(message_id.is_server());
9020     switch (dialog_id.get_type()) {
9021       case DialogType::Channel:
9022         // get channel difference may prevent updates from being applied
9023         if (running_get_channel_difference(dialog_id)) {
9024           break;
9025         }
9026       // fallthrough
9027       case DialogType::User:
9028       case DialogType::Chat: {
9029         if (!have_message_force({dialog_id, it.second}, "after get difference")) {
9030           // The sent message has already been deleted by the user or sent to inaccessible channel.
9031           // The sent message may never be received, but we will need updateMessageId in case the message is received
9032           // to delete it from the server and not add to the chat.
9033           // But if the chat is inaccessible or the message is in an inaccessible chat part, then we will not be able to
9034           // add the message or delete it from the server. In this case we forget updateMessageId for such messages in
9035           // order to not check them over and over.
9036           const Dialog *d = get_dialog(dialog_id);
9037           if (!have_input_peer(dialog_id, AccessRights::Read) ||
9038               (d != nullptr &&
9039                message_id <= td::max(d->last_clear_history_message_id, d->max_unavailable_message_id))) {
9040             update_message_ids_to_delete.push_back(it.first);
9041           }
9042           break;
9043         }
9044 
9045         const Dialog *d = get_dialog(dialog_id);
9046         CHECK(d != nullptr);
9047         if (dialog_id.get_type() == DialogType::Channel || message_id <= d->last_new_message_id) {
9048           LOG(ERROR) << "Receive updateMessageId from " << it.second << " to " << full_message_id
9049                      << " but not receive corresponding message, last_new_message_id = " << d->last_new_message_id;
9050         }
9051         if (dialog_id.get_type() != DialogType::Channel && message_id <= d->last_new_message_id) {
9052           dump_debug_message_op(get_dialog(dialog_id));
9053         }
9054         if (message_id <= d->last_new_message_id) {
9055           get_message_from_server(it.first, PromiseCreator::lambda([full_message_id](Result<Unit> result) {
9056                                     if (result.is_error()) {
9057                                       LOG(WARNING)
9058                                           << "Failed to get missing " << full_message_id << ": " << result.error();
9059                                     } else {
9060                                       LOG(WARNING) << "Successfully get missing " << full_message_id;
9061                                     }
9062                                   }),
9063                                   "get missing");
9064         } else if (dialog_id.get_type() == DialogType::Channel) {
9065           LOG(INFO) << "Schedule getDifference in " << dialog_id.get_channel_id();
9066           channel_get_difference_retry_timeout_.add_timeout_in(dialog_id.get(), 0.001);
9067         }
9068         break;
9069       }
9070       case DialogType::SecretChat:
9071         break;
9072       case DialogType::None:
9073       default:
9074         UNREACHABLE();
9075         break;
9076     }
9077   }
9078   for (const auto &full_message_id : update_message_ids_to_delete) {
9079     update_message_ids_.erase(full_message_id);
9080   }
9081 
9082   if (!td_->auth_manager_->is_bot()) {
9083     if (!G()->td_db()->get_binlog_pmc()->isset("fetched_marks_as_unread")) {
9084       td_->create_handler<GetDialogUnreadMarksQuery>()->send();
9085     }
9086 
9087     load_notification_settings();
9088 
9089     auto dialog_list_id = DialogListId(FolderId::archive());
9090     auto *list = get_dialog_list(dialog_list_id);
9091     CHECK(list != nullptr);
9092     if (!list->is_dialog_unread_count_inited_) {
9093       int32 limit = list->are_pinned_dialogs_inited_ ? static_cast<int32>(list->pinned_dialogs_.size())
9094                                                      : get_pinned_dialogs_limit(dialog_list_id);
9095       LOG(INFO) << "Loading chat list in " << dialog_list_id << " to init total unread count";
9096       get_dialogs_from_list(dialog_list_id, limit + 2, Auto());
9097     }
9098   }
9099 }
9100 
on_get_empty_messages(DialogId dialog_id,const vector<MessageId> & empty_message_ids)9101 void MessagesManager::on_get_empty_messages(DialogId dialog_id, const vector<MessageId> &empty_message_ids) {
9102   if (!empty_message_ids.empty()) {
9103     delete_dialog_messages(dialog_id, empty_message_ids, true, true, "on_get_empty_messages");
9104   }
9105 }
9106 
get_messages_info(tl_object_ptr<telegram_api::messages_Messages> && messages_ptr,const char * source)9107 MessagesManager::MessagesInfo MessagesManager::get_messages_info(
9108     tl_object_ptr<telegram_api::messages_Messages> &&messages_ptr, const char *source) {
9109   CHECK(messages_ptr != nullptr);
9110   LOG(DEBUG) << "Receive result for " << source << ": " << to_string(messages_ptr);
9111 
9112   vector<tl_object_ptr<telegram_api::User>> users;
9113   vector<tl_object_ptr<telegram_api::Chat>> chats;
9114   MessagesInfo result;
9115   switch (messages_ptr->get_id()) {
9116     case telegram_api::messages_messages::ID: {
9117       auto messages = move_tl_object_as<telegram_api::messages_messages>(messages_ptr);
9118 
9119       users = std::move(messages->users_);
9120       chats = std::move(messages->chats_);
9121       result.total_count = narrow_cast<int32>(messages->messages_.size());
9122       result.messages = std::move(messages->messages_);
9123       break;
9124     }
9125     case telegram_api::messages_messagesSlice::ID: {
9126       auto messages = move_tl_object_as<telegram_api::messages_messagesSlice>(messages_ptr);
9127 
9128       users = std::move(messages->users_);
9129       chats = std::move(messages->chats_);
9130       result.total_count = messages->count_;
9131       result.messages = std::move(messages->messages_);
9132       break;
9133     }
9134     case telegram_api::messages_channelMessages::ID: {
9135       auto messages = move_tl_object_as<telegram_api::messages_channelMessages>(messages_ptr);
9136 
9137       users = std::move(messages->users_);
9138       chats = std::move(messages->chats_);
9139       result.total_count = messages->count_;
9140       result.messages = std::move(messages->messages_);
9141       result.is_channel_messages = true;
9142       break;
9143     }
9144     case telegram_api::messages_messagesNotModified::ID:
9145       LOG(ERROR) << "Server returned messagesNotModified in response to " << source;
9146       break;
9147     default:
9148       UNREACHABLE();
9149       break;
9150   }
9151 
9152   td_->contacts_manager_->on_get_users(std::move(users), source);
9153   td_->contacts_manager_->on_get_chats(std::move(chats), source);
9154 
9155   return result;
9156 }
9157 
get_channel_difference_if_needed(DialogId dialog_id,MessagesInfo && messages_info,Promise<MessagesInfo> && promise)9158 void MessagesManager::get_channel_difference_if_needed(DialogId dialog_id, MessagesInfo &&messages_info,
9159                                                        Promise<MessagesInfo> &&promise) {
9160   for (auto &message : messages_info.messages) {
9161     if (need_channel_difference_to_add_message(dialog_id, message)) {
9162       return run_after_channel_difference(
9163           dialog_id,
9164           PromiseCreator::lambda([messages_info = std::move(messages_info), promise = std::move(promise)](
9165                                      Unit ignored) mutable { promise.set_value(std::move(messages_info)); }));
9166     }
9167   }
9168   promise.set_value(std::move(messages_info));
9169 }
9170 
get_channel_differences_if_needed(MessagesInfo && messages_info,Promise<MessagesInfo> && promise)9171 void MessagesManager::get_channel_differences_if_needed(MessagesInfo &&messages_info, Promise<MessagesInfo> &&promise) {
9172   MultiPromiseActorSafe mpas{"GetChannelDifferencesIfNeededMultiPromiseActor"};
9173   mpas.add_promise(Promise<Unit>());
9174   mpas.set_ignore_errors(true);
9175   auto lock = mpas.get_promise();
9176   for (auto &message : messages_info.messages) {
9177     if (message == nullptr) {
9178       continue;
9179     }
9180 
9181     auto dialog_id = get_message_dialog_id(message);
9182     if (need_channel_difference_to_add_message(dialog_id, message)) {
9183       run_after_channel_difference(dialog_id, mpas.get_promise());
9184     }
9185   }
9186   // must be added after messages_info is checked
9187   mpas.add_promise(PromiseCreator::lambda([messages_info = std::move(messages_info), promise = std::move(promise)](
9188                                               Unit ignored) mutable { promise.set_value(std::move(messages_info)); }));
9189   lock.set_value(Unit());
9190 }
9191 
on_get_messages(vector<tl_object_ptr<telegram_api::Message>> && messages,bool is_channel_message,bool is_scheduled,Promise<Unit> && promise,const char * source)9192 void MessagesManager::on_get_messages(vector<tl_object_ptr<telegram_api::Message>> &&messages, bool is_channel_message,
9193                                       bool is_scheduled, Promise<Unit> &&promise, const char *source) {
9194   TRY_STATUS_PROMISE(promise, G()->close_status());
9195 
9196   LOG(DEBUG) << "Receive " << messages.size() << " messages";
9197   for (auto &message : messages) {
9198     on_get_message(std::move(message), false, is_channel_message, is_scheduled, false, false, source);
9199   }
9200   promise.set_value(Unit());
9201 }
9202 
delete_newer_server_messages_at_the_end(Dialog * d,MessageId max_message_id)9203 bool MessagesManager::delete_newer_server_messages_at_the_end(Dialog *d, MessageId max_message_id) {
9204   vector<MessageId> message_ids;
9205   find_newer_messages(d->messages.get(), max_message_id, message_ids);
9206   if (message_ids.empty()) {
9207     return false;
9208   }
9209 
9210   bool need_update_dialog_pos = false;
9211   vector<int64> deleted_message_ids;
9212   for (auto message_id : message_ids) {
9213     CHECK(message_id > max_message_id);
9214     if (message_id.is_server()) {
9215       auto message =
9216           delete_message(d, message_id, true, &need_update_dialog_pos, "delete_newer_server_messages_at_the_end 1");
9217       CHECK(message != nullptr);
9218       deleted_message_ids.push_back(message->message_id.get());
9219     }
9220   }
9221   if (need_update_dialog_pos) {
9222     send_update_chat_last_message(d, "delete_newer_server_messages_at_the_end 2");
9223   }
9224 
9225   if (!deleted_message_ids.empty()) {
9226     send_update_delete_messages(d->dialog_id, std::move(deleted_message_ids), true, false);
9227 
9228     message_ids.clear();
9229     find_newer_messages(d->messages.get(), max_message_id, message_ids);
9230   }
9231 
9232   // connect all messages with ID > max_message_id
9233   for (size_t i = 0; i + 1 < message_ids.size(); i++) {
9234     auto m = get_message(d, message_ids[i]);
9235     CHECK(m != nullptr);
9236     if (!m->have_next) {
9237       m->have_next = true;
9238       attach_message_to_next(d, message_ids[i], "delete_newer_server_messages_at_the_end 3");
9239     }
9240   }
9241 
9242   return !message_ids.empty();
9243 }
9244 
on_get_history(DialogId dialog_id,MessageId from_message_id,MessageId old_last_new_message_id,int32 offset,int32 limit,bool from_the_end,vector<tl_object_ptr<telegram_api::Message>> && messages,Promise<Unit> && promise)9245 void MessagesManager::on_get_history(DialogId dialog_id, MessageId from_message_id, MessageId old_last_new_message_id,
9246                                      int32 offset, int32 limit, bool from_the_end,
9247                                      vector<tl_object_ptr<telegram_api::Message>> &&messages, Promise<Unit> &&promise) {
9248   TRY_STATUS_PROMISE(promise, G()->close_status());
9249 
9250   LOG(INFO) << "Receive " << messages.size() << " history messages " << (from_the_end ? "from the end " : "") << "in "
9251             << dialog_id << " from " << from_message_id << " with offset " << offset << " and limit " << limit;
9252   CHECK(-limit < offset && offset <= 0);
9253   CHECK(offset < 0 || from_the_end);
9254   CHECK(!from_message_id.is_scheduled());
9255 
9256   Dialog *d = get_dialog(dialog_id);
9257   CHECK(d != nullptr);
9258 
9259   MessageId last_received_message_id = messages.empty() ? MessageId() : get_message_id(messages[0], false);
9260   if (old_last_new_message_id < d->last_new_message_id && (from_the_end || old_last_new_message_id < from_message_id) &&
9261       last_received_message_id < d->last_new_message_id) {
9262     // new server messages were added to the dialog since the request was sent, but weren't received
9263     // they should have been received, so we must repeat the request to get them
9264     if (from_the_end) {
9265       get_history_from_the_end_impl(d, false, false, std::move(promise));
9266     } else {
9267       get_history_impl(d, from_message_id, offset, limit, false, false, std::move(promise));
9268     }
9269     return;
9270   }
9271 
9272   // the server can return less messages than requested if some of messages are deleted during request
9273   // but if it happens, it is likely that there are no more messages on the server
9274   bool have_full_history = from_the_end && narrow_cast<int32>(messages.size()) < limit && messages.size() <= 1;
9275 
9276   if (messages.empty()) {
9277     if (have_full_history) {
9278       d->have_full_history = true;
9279       on_dialog_updated(dialog_id, "set have_full_history");
9280     }
9281 
9282     if (from_the_end && d->have_full_history && d->messages == nullptr) {
9283       if (!d->last_database_message_id.is_valid()) {
9284         set_dialog_is_empty(d, "on_get_history empty");
9285       } else {
9286         LOG(INFO) << "Skip marking " << dialog_id << " as empty, because it probably has messages from "
9287                   << d->first_database_message_id << " to " << d->last_database_message_id << " in the database";
9288       }
9289     }
9290 
9291     // be aware that in some cases an empty answer may be returned, because of the race of getHistory and deleteMessages
9292     // and not because there are no more messages
9293     promise.set_value(Unit());
9294     return;
9295   }
9296 
9297   if (messages.size() > 1) {
9298     // check that messages are received in decreasing message_id order
9299     MessageId cur_message_id = MessageId::max();
9300     for (const auto &message : messages) {
9301       MessageId message_id = get_message_id(message, false);
9302       if (message_id >= cur_message_id) {
9303         string error = PSTRING() << "Receive messages in the wrong order in history of " << dialog_id << " from "
9304                                  << from_message_id << " with offset " << offset << ", limit " << limit
9305                                  << ", from_the_end = " << from_the_end << ": ";
9306         for (const auto &debug_message : messages) {
9307           error += to_string(debug_message);
9308         }
9309         // TODO move to ERROR
9310         LOG(FATAL) << error;
9311         promise.set_value(Unit());
9312         return;
9313       }
9314       cur_message_id = message_id;
9315     }
9316   }
9317 
9318   // be aware that returned messages are guaranteed to be consecutive messages, but if !from_the_end they
9319   // may be older (if some messages was deleted) or newer (if some messages were added) than an expected answer
9320   // be aware that any subset of the returned messages may be already deleted and returned as MessageEmpty
9321   bool is_channel_message = dialog_id.get_type() == DialogType::Channel;
9322   MessageId first_added_message_id;
9323   MessageId last_added_message_id;
9324   bool have_next = false;
9325 
9326   if (narrow_cast<int32>(messages.size()) < limit + offset && messages.size() <= 1) {
9327     MessageId first_received_message_id = get_message_id(messages.back(), false);
9328     if (first_received_message_id >= from_message_id && d->first_database_message_id.is_valid() &&
9329         first_received_message_id >= d->first_database_message_id) {
9330       // it is likely that there are no more history messages on the server
9331       have_full_history = true;
9332     }
9333   }
9334 
9335   bool prev_have_full_history = d->have_full_history;
9336   MessageId prev_last_new_message_id = d->last_new_message_id;
9337   MessageId prev_first_database_message_id = d->first_database_message_id;
9338   MessageId prev_last_database_message_id = d->last_database_message_id;
9339   MessageId prev_last_message_id = d->last_message_id;
9340   if (from_the_end) {
9341     // delete all server messages with ID > last_received_message_id
9342     // there were no new messages received after the getHistory request was sent, so they are already deleted message
9343     if (delete_newer_server_messages_at_the_end(d, last_received_message_id)) {
9344       have_next = true;
9345     }
9346   }
9347 
9348   for (auto &message : messages) {
9349     if (!have_next && from_the_end && get_message_id(message, false) < d->last_message_id) {
9350       // last message in the dialog should be attached to the next message if there is some
9351       have_next = true;
9352     }
9353 
9354     auto message_dialog_id = get_message_dialog_id(message);
9355     if (message_dialog_id != dialog_id) {
9356       LOG(ERROR) << "Receive " << get_message_id(message, false) << " in wrong " << message_dialog_id << " instead of "
9357                  << dialog_id << ": " << oneline(to_string(message));
9358       continue;
9359     }
9360 
9361     auto full_message_id =
9362         on_get_message(std::move(message), false, is_channel_message, false, false, have_next, "get history");
9363     auto message_id = full_message_id.get_message_id();
9364     if (message_id.is_valid()) {
9365       if (!last_added_message_id.is_valid()) {
9366         last_added_message_id = message_id;
9367       }
9368 
9369       if (!have_next) {
9370         have_next = true;
9371       } else if (first_added_message_id.is_valid()) {
9372         Message *next_message = get_message(d, first_added_message_id);
9373         CHECK(next_message != nullptr);
9374         if (!next_message->have_previous) {
9375           LOG(INFO) << "Fix have_previous for " << first_added_message_id;
9376           next_message->have_previous = true;
9377           attach_message_to_previous(d, first_added_message_id, "on_get_history");
9378         }
9379       }
9380       first_added_message_id = message_id;
9381       if (!message_id.is_yet_unsent()) {
9382         // message should be already saved to database in on_get_message
9383         // add_message_to_database(d, get_message(d, message_id), "on_get_history");
9384       }
9385     }
9386   }
9387 
9388   if (from_the_end && last_added_message_id.is_valid() && last_added_message_id != last_received_message_id) {
9389     CHECK(last_added_message_id < last_received_message_id);
9390     delete_newer_server_messages_at_the_end(d, last_added_message_id);
9391   }
9392 
9393   if (have_full_history) {
9394     d->have_full_history = true;
9395     on_dialog_updated(dialog_id, "set have_full_history 2");
9396   }
9397 
9398   //  LOG_IF(ERROR, d->first_message_id.is_valid() && d->first_message_id > first_received_message_id)
9399   //      << "Receive " << first_received_message_id << ", but first chat message is " << d->first_message_id;
9400 
9401   if (from_the_end && !d->last_new_message_id.is_valid()) {
9402     set_dialog_last_new_message_id(
9403         d, last_added_message_id.is_valid() ? last_added_message_id : last_received_message_id, "on_get_history");
9404   }
9405   bool intersect_last_database_message_ids =
9406       last_added_message_id >= d->first_database_message_id && d->last_database_message_id >= first_added_message_id;
9407   bool need_update_database_message_ids =
9408       last_added_message_id.is_valid() && (from_the_end || intersect_last_database_message_ids);
9409   if (from_the_end && last_added_message_id.is_valid() && last_added_message_id > d->last_message_id) {
9410     CHECK(d->last_new_message_id.is_valid());
9411     set_dialog_last_message_id(d, last_added_message_id, "on_get_history");
9412     send_update_chat_last_message(d, "on_get_history");
9413   }
9414 
9415   if (need_update_database_message_ids) {
9416     if (from_the_end && !intersect_last_database_message_ids && d->last_database_message_id.is_valid()) {
9417       if (d->last_database_message_id < first_added_message_id || last_added_message_id == d->last_message_id) {
9418         set_dialog_first_database_message_id(d, MessageId(), "on_get_history 1");
9419         set_dialog_last_database_message_id(d, MessageId(), "on_get_history 1");
9420       } else {
9421         auto min_message_id = td::min(d->first_database_message_id, d->last_message_id);
9422         LOG_CHECK(last_added_message_id < min_message_id)
9423             << need_update_database_message_ids << ' ' << first_added_message_id << ' ' << last_added_message_id << ' '
9424             << d->first_database_message_id << ' ' << d->last_database_message_id << ' ' << d->last_new_message_id
9425             << ' ' << d->last_message_id << ' ' << prev_first_database_message_id << ' '
9426             << prev_last_database_message_id << ' ' << prev_last_new_message_id << ' ' << prev_last_message_id;
9427         if (min_message_id <= last_added_message_id.get_next_message_id(MessageType::Server)) {
9428           // connect local messages with last received server message
9429           set_dialog_first_database_message_id(d, last_added_message_id, "on_get_history 2");
9430         } else {
9431           LOG(WARNING) << "Have last " << d->last_message_id << " and first database " << d->first_database_message_id
9432                        << " in " << dialog_id << ", but received history from the end only up to "
9433                        << last_added_message_id;
9434           // can't connect messages, because there can be unknown server messages after last_added_message_id
9435         }
9436       }
9437     }
9438     if (!d->last_database_message_id.is_valid()) {
9439       CHECK(d->last_message_id.is_valid());
9440       MessagesConstIterator it(d, d->last_message_id);
9441       MessageId new_first_database_message_id;
9442       while (*it != nullptr) {
9443         auto message_id = (*it)->message_id;
9444         if (message_id.is_server() || message_id.is_local()) {
9445           if (!d->last_database_message_id.is_valid()) {
9446             set_dialog_last_database_message_id(d, message_id, "on_get_history");
9447           }
9448           new_first_database_message_id = message_id;
9449           try_restore_dialog_reply_markup(d, *it);
9450         }
9451         --it;
9452       }
9453       if (new_first_database_message_id.is_valid()) {
9454         set_dialog_first_database_message_id(d, new_first_database_message_id, "on_get_history");
9455       }
9456     } else {
9457       LOG_CHECK(d->last_new_message_id.is_valid())
9458           << dialog_id << " " << from_the_end << " " << d->first_database_message_id << " "
9459           << d->last_database_message_id << " " << first_added_message_id << " " << last_added_message_id << " "
9460           << d->last_message_id << " " << d->last_new_message_id << " " << d->have_full_history << " "
9461           << prev_last_new_message_id << " " << prev_first_database_message_id << " " << prev_last_database_message_id
9462           << " " << prev_last_message_id << " " << prev_have_full_history << " " << d->debug_last_new_message_id << " "
9463           << d->debug_first_database_message_id << " " << d->debug_last_database_message_id << " " << from_message_id
9464           << " " << offset << " " << limit << " " << messages.size() << " " << last_received_message_id << " "
9465           << d->debug_set_dialog_last_database_message_id;
9466       CHECK(d->first_database_message_id.is_valid());
9467       {
9468         MessagesConstIterator it(d, d->first_database_message_id);
9469         if (*it != nullptr && ((*it)->message_id == d->first_database_message_id || (*it)->have_next)) {
9470           MessageId new_first_database_message_id = d->first_database_message_id;
9471           while (*it != nullptr) {
9472             auto message_id = (*it)->message_id;
9473             if ((message_id.is_server() || message_id.is_local()) && message_id < new_first_database_message_id) {
9474               new_first_database_message_id = message_id;
9475               try_restore_dialog_reply_markup(d, *it);
9476             }
9477             --it;
9478           }
9479           if (new_first_database_message_id != d->first_database_message_id) {
9480             set_dialog_first_database_message_id(d, new_first_database_message_id, "on_get_history 2");
9481           }
9482         }
9483       }
9484       {
9485         MessagesConstIterator it(d, d->last_database_message_id);
9486         if (*it != nullptr && ((*it)->message_id == d->last_database_message_id || (*it)->have_next)) {
9487           MessageId new_last_database_message_id = d->last_database_message_id;
9488           while (*it != nullptr) {
9489             auto message_id = (*it)->message_id;
9490             if ((message_id.is_server() || message_id.is_local()) && message_id > new_last_database_message_id) {
9491               new_last_database_message_id = message_id;
9492             }
9493             ++it;
9494           }
9495           if (new_last_database_message_id != d->last_database_message_id) {
9496             set_dialog_last_database_message_id(d, new_last_database_message_id, "on_get_history 2");
9497           }
9498         }
9499       }
9500     }
9501     LOG_CHECK(d->first_database_message_id.is_valid())
9502         << dialog_id << " " << from_the_end << " " << d->first_database_message_id << " " << d->last_database_message_id
9503         << " " << first_added_message_id << " " << last_added_message_id << " " << d->last_message_id << " "
9504         << d->last_new_message_id << " " << d->have_full_history << " " << prev_last_new_message_id << " "
9505         << prev_first_database_message_id << " " << prev_last_database_message_id << " " << prev_last_message_id << " "
9506         << prev_have_full_history << " " << d->debug_last_new_message_id << " " << d->debug_first_database_message_id
9507         << " " << d->debug_last_database_message_id << " " << from_message_id << " " << offset << " " << limit << " "
9508         << messages.size() << " " << last_received_message_id << " " << d->debug_set_dialog_last_database_message_id;
9509     CHECK(d->last_database_message_id.is_valid());
9510 
9511     for (auto &first_message_id : d->first_database_message_id_by_index) {
9512       if (first_added_message_id < first_message_id && first_message_id <= last_added_message_id) {
9513         first_message_id = first_added_message_id;
9514       }
9515     }
9516   }
9517   promise.set_value(Unit());
9518 }
9519 
get_peers_dialog_ids(vector<tl_object_ptr<telegram_api::Peer>> && peers)9520 vector<DialogId> MessagesManager::get_peers_dialog_ids(vector<tl_object_ptr<telegram_api::Peer>> &&peers) {
9521   vector<DialogId> result;
9522   result.reserve(peers.size());
9523   for (auto &peer : peers) {
9524     DialogId dialog_id(peer);
9525     if (dialog_id.is_valid()) {
9526       force_create_dialog(dialog_id, "get_peers_dialog_ids");
9527       result.push_back(dialog_id);
9528     }
9529   }
9530   return result;
9531 }
9532 
on_get_public_dialogs_search_result(const string & query,vector<tl_object_ptr<telegram_api::Peer>> && my_peers,vector<tl_object_ptr<telegram_api::Peer>> && peers)9533 void MessagesManager::on_get_public_dialogs_search_result(const string &query,
9534                                                           vector<tl_object_ptr<telegram_api::Peer>> &&my_peers,
9535                                                           vector<tl_object_ptr<telegram_api::Peer>> &&peers) {
9536   auto it = search_public_dialogs_queries_.find(query);
9537   CHECK(it != search_public_dialogs_queries_.end());
9538   CHECK(!it->second.empty());
9539   auto promises = std::move(it->second);
9540   search_public_dialogs_queries_.erase(it);
9541 
9542   found_public_dialogs_[query] = get_peers_dialog_ids(std::move(peers));
9543   found_on_server_dialogs_[query] = get_peers_dialog_ids(std::move(my_peers));
9544 
9545   for (auto &promise : promises) {
9546     promise.set_value(Unit());
9547   }
9548 }
9549 
on_failed_public_dialogs_search(const string & query,Status && error)9550 void MessagesManager::on_failed_public_dialogs_search(const string &query, Status &&error) {
9551   auto it = search_public_dialogs_queries_.find(query);
9552   CHECK(it != search_public_dialogs_queries_.end());
9553   CHECK(!it->second.empty());
9554   auto promises = std::move(it->second);
9555   search_public_dialogs_queries_.erase(it);
9556 
9557   found_public_dialogs_[query];     // negative cache
9558   found_on_server_dialogs_[query];  // negative cache
9559 
9560   for (auto &promise : promises) {
9561     promise.set_error(error.clone());
9562   }
9563 }
9564 
on_get_message_search_result_calendar(DialogId dialog_id,MessageId from_message_id,MessageSearchFilter filter,int64 random_id,int32 total_count,vector<tl_object_ptr<telegram_api::Message>> && messages,vector<tl_object_ptr<telegram_api::searchResultsCalendarPeriod>> && periods,Promise<Unit> && promise)9565 void MessagesManager::on_get_message_search_result_calendar(
9566     DialogId dialog_id, MessageId from_message_id, MessageSearchFilter filter, int64 random_id, int32 total_count,
9567     vector<tl_object_ptr<telegram_api::Message>> &&messages,
9568     vector<tl_object_ptr<telegram_api::searchResultsCalendarPeriod>> &&periods, Promise<Unit> &&promise) {
9569   TRY_STATUS_PROMISE(promise, G()->close_status());
9570 
9571   auto it = found_dialog_message_calendars_.find(random_id);
9572   CHECK(it != found_dialog_message_calendars_.end());
9573 
9574   int32 received_message_count = 0;
9575   for (auto &message : messages) {
9576     auto new_full_message_id = on_get_message(std::move(message), false, dialog_id.get_type() == DialogType::Channel,
9577                                               false, false, false, "on_get_message_search_result_calendar");
9578     if (new_full_message_id == FullMessageId()) {
9579       total_count--;
9580       continue;
9581     }
9582 
9583     if (new_full_message_id.get_dialog_id() != dialog_id) {
9584       LOG(ERROR) << "Receive " << new_full_message_id << " instead of a message in " << dialog_id;
9585       total_count--;
9586       continue;
9587     }
9588 
9589     received_message_count++;
9590   }
9591   if (total_count < received_message_count) {
9592     LOG(ERROR) << "Receive " << received_message_count << " valid messages out of " << total_count << " in "
9593                << messages.size() << " messages";
9594     total_count = received_message_count;
9595   }
9596 
9597   Dialog *d = get_dialog(dialog_id);
9598   CHECK(d != nullptr);
9599   auto &old_message_count = d->message_count_by_index[message_search_filter_index(filter)];
9600   if (old_message_count != total_count) {
9601     old_message_count = total_count;
9602     on_dialog_updated(dialog_id, "on_get_message_search_result_calendar");
9603   }
9604 
9605   vector<td_api::object_ptr<td_api::messageCalendarDay>> days;
9606   for (auto &period : periods) {
9607     auto message_id = MessageId(ServerMessageId(period->min_msg_id_));
9608     const auto *m = get_message(d, message_id);
9609     if (m == nullptr) {
9610       LOG(ERROR) << "Failed to find " << message_id;
9611       continue;
9612     }
9613     if (period->count_ <= 0) {
9614       LOG(ERROR) << "Receive " << to_string(period);
9615       continue;
9616     }
9617     days.push_back(td_api::make_object<td_api::messageCalendarDay>(
9618         period->count_, get_message_object(dialog_id, m, "on_get_message_search_result_calendar")));
9619   }
9620   it->second = td_api::make_object<td_api::messageCalendar>(total_count, std::move(days));
9621   promise.set_value(Unit());
9622 }
9623 
on_failed_get_message_search_result_calendar(DialogId dialog_id,int64 random_id)9624 void MessagesManager::on_failed_get_message_search_result_calendar(DialogId dialog_id, int64 random_id) {
9625   auto it = found_dialog_message_calendars_.find(random_id);
9626   CHECK(it != found_dialog_message_calendars_.end());
9627   found_dialog_message_calendars_.erase(it);
9628 }
9629 
on_get_dialog_messages_search_result(DialogId dialog_id,const string & query,DialogId sender_dialog_id,MessageId from_message_id,int32 offset,int32 limit,MessageSearchFilter filter,MessageId top_thread_message_id,int64 random_id,int32 total_count,vector<tl_object_ptr<telegram_api::Message>> && messages,Promise<Unit> && promise)9630 void MessagesManager::on_get_dialog_messages_search_result(
9631     DialogId dialog_id, const string &query, DialogId sender_dialog_id, MessageId from_message_id, int32 offset,
9632     int32 limit, MessageSearchFilter filter, MessageId top_thread_message_id, int64 random_id, int32 total_count,
9633     vector<tl_object_ptr<telegram_api::Message>> &&messages, Promise<Unit> &&promise) {
9634   TRY_STATUS_PROMISE(promise, G()->close_status());
9635 
9636   LOG(INFO) << "Receive " << messages.size() << " found messages in " << dialog_id;
9637   if (!dialog_id.is_valid()) {
9638     CHECK(query.empty());
9639     CHECK(!sender_dialog_id.is_valid());
9640     CHECK(!top_thread_message_id.is_valid());
9641     auto it = found_call_messages_.find(random_id);
9642     CHECK(it != found_call_messages_.end());
9643 
9644     MessageId first_added_message_id;
9645     if (messages.empty()) {
9646       // messages may be empty because there are no more messages or they can't be found due to global limit
9647       // anyway pretend that there are no more messages
9648       first_added_message_id = MessageId::min();
9649     }
9650 
9651     auto &result = it->second.second;
9652     CHECK(result.empty());
9653     int32 added_message_count = 0;
9654     for (auto &message : messages) {
9655       auto new_full_message_id =
9656           on_get_message(std::move(message), false, false, false, false, false, "search call messages");
9657       if (new_full_message_id != FullMessageId()) {
9658         result.push_back(new_full_message_id);
9659         added_message_count++;
9660       }
9661 
9662       auto message_id = new_full_message_id.get_message_id();
9663       if (message_id < first_added_message_id || !first_added_message_id.is_valid()) {
9664         first_added_message_id = message_id;
9665       }
9666     }
9667     if (total_count < added_message_count) {
9668       LOG(ERROR) << "Receive total_count = " << total_count << ", but added " << added_message_count
9669                  << " messages out of " << messages.size();
9670       total_count = added_message_count;
9671     }
9672     if (G()->parameters().use_message_db) {
9673       bool update_state = false;
9674 
9675       auto &old_message_count = calls_db_state_.message_count_by_index[call_message_search_filter_index(filter)];
9676       if (old_message_count != total_count) {
9677         LOG(INFO) << "Update calls database message count to " << total_count;
9678         old_message_count = total_count;
9679         update_state = true;
9680       }
9681 
9682       auto &old_first_db_message_id =
9683           calls_db_state_.first_calls_database_message_id_by_index[call_message_search_filter_index(filter)];
9684       bool from_the_end = !from_message_id.is_valid() || from_message_id >= MessageId::max();
9685       LOG(INFO) << "Have from_the_end = " << from_the_end << ", old_first_db_message_id = " << old_first_db_message_id
9686                 << ", first_added_message_id = " << first_added_message_id << ", from_message_id = " << from_message_id;
9687       if ((from_the_end || (old_first_db_message_id.is_valid() && old_first_db_message_id <= from_message_id)) &&
9688           (!old_first_db_message_id.is_valid() || first_added_message_id < old_first_db_message_id)) {
9689         LOG(INFO) << "Update calls database first message to " << first_added_message_id;
9690         old_first_db_message_id = first_added_message_id;
9691         update_state = true;
9692       }
9693       if (update_state) {
9694         save_calls_db_state();
9695       }
9696     }
9697     it->second.first = total_count;
9698     promise.set_value(Unit());
9699     return;
9700   }
9701 
9702   auto it = found_dialog_messages_.find(random_id);
9703   CHECK(it != found_dialog_messages_.end());
9704 
9705   auto &result = it->second.second;
9706   CHECK(result.empty());
9707   MessageId first_added_message_id;
9708   if (messages.empty()) {
9709     // messages may be empty because there are no more messages or they can't be found due to global limit
9710     // anyway pretend that there are no more messages
9711     first_added_message_id = MessageId::min();
9712   }
9713   bool can_be_in_different_dialog = top_thread_message_id.is_valid() && is_broadcast_channel(dialog_id);
9714   DialogId real_dialog_id;
9715   Dialog *d = get_dialog(dialog_id);
9716   CHECK(d != nullptr);
9717   for (auto &message : messages) {
9718     auto new_full_message_id = on_get_message(std::move(message), false, dialog_id.get_type() == DialogType::Channel,
9719                                               false, false, false, "on_get_dialog_messages_search_result");
9720     if (new_full_message_id == FullMessageId()) {
9721       total_count--;
9722       continue;
9723     }
9724 
9725     if (new_full_message_id.get_dialog_id() != dialog_id) {
9726       if (!can_be_in_different_dialog) {
9727         LOG(ERROR) << "Receive " << new_full_message_id << " instead of a message in " << dialog_id;
9728         total_count--;
9729         continue;
9730       } else {
9731         if (!real_dialog_id.is_valid()) {
9732           real_dialog_id = new_full_message_id.get_dialog_id();
9733           found_dialog_messages_dialog_id_[random_id] = real_dialog_id;
9734         } else if (new_full_message_id.get_dialog_id() != real_dialog_id) {
9735           LOG(ERROR) << "Receive " << new_full_message_id << " instead of a message in " << real_dialog_id << " or "
9736                      << dialog_id;
9737           total_count--;
9738           continue;
9739         }
9740       }
9741     }
9742 
9743     auto message_id = new_full_message_id.get_message_id();
9744     if (filter == MessageSearchFilter::UnreadMention && message_id <= d->last_read_all_mentions_message_id &&
9745         !real_dialog_id.is_valid()) {
9746       total_count--;
9747       continue;
9748     }
9749 
9750     // TODO check that messages are returned in decreasing message_id order
9751     if (message_id < first_added_message_id || !first_added_message_id.is_valid()) {
9752       first_added_message_id = message_id;
9753     }
9754     result.push_back(message_id);
9755   }
9756   if (total_count < static_cast<int32>(result.size())) {
9757     LOG(ERROR) << "Receive " << result.size() << " valid messages out of " << total_count << " in " << messages.size()
9758                << " messages";
9759     total_count = static_cast<int32>(result.size());
9760   }
9761   if (query.empty() && !sender_dialog_id.is_valid() && filter != MessageSearchFilter::Empty &&
9762       !top_thread_message_id.is_valid()) {
9763     bool from_the_end = !from_message_id.is_valid() ||
9764                         (d->last_message_id != MessageId() && from_message_id > d->last_message_id) ||
9765                         from_message_id >= MessageId::max();
9766     bool update_dialog = false;
9767 
9768     auto &old_message_count = d->message_count_by_index[message_search_filter_index(filter)];
9769     if (old_message_count != total_count) {
9770       old_message_count = total_count;
9771       if (filter == MessageSearchFilter::UnreadMention) {
9772         d->unread_mention_count = old_message_count;
9773         update_dialog_mention_notification_count(d);
9774         send_update_chat_unread_mention_count(d);
9775       }
9776       update_dialog = true;
9777     }
9778 
9779     auto &old_first_database_message_id = d->first_database_message_id_by_index[message_search_filter_index(filter)];
9780     if ((from_the_end ||
9781          (old_first_database_message_id.is_valid() && old_first_database_message_id <= from_message_id)) &&
9782         (!old_first_database_message_id.is_valid() || first_added_message_id < old_first_database_message_id)) {
9783       old_first_database_message_id = first_added_message_id;
9784       update_dialog = true;
9785     }
9786     if (update_dialog) {
9787       on_dialog_updated(dialog_id, "search results");
9788     }
9789 
9790     if (from_the_end && filter == MessageSearchFilter::Pinned) {
9791       set_dialog_last_pinned_message_id(d, result.empty() ? MessageId() : result[0]);
9792     }
9793   }
9794 
9795   it->second.first = total_count;
9796   promise.set_value(Unit());
9797 }
9798 
on_failed_dialog_messages_search(DialogId dialog_id,int64 random_id)9799 void MessagesManager::on_failed_dialog_messages_search(DialogId dialog_id, int64 random_id) {
9800   if (!dialog_id.is_valid()) {
9801     auto it = found_call_messages_.find(random_id);
9802     CHECK(it != found_call_messages_.end());
9803     found_call_messages_.erase(it);
9804     return;
9805   }
9806 
9807   auto it = found_dialog_messages_.find(random_id);
9808   CHECK(it != found_dialog_messages_.end());
9809   found_dialog_messages_.erase(it);
9810 }
9811 
on_get_dialog_message_count(DialogId dialog_id,MessageSearchFilter filter,int32 total_count,Promise<int32> && promise)9812 void MessagesManager::on_get_dialog_message_count(DialogId dialog_id, MessageSearchFilter filter, int32 total_count,
9813                                                   Promise<int32> &&promise) {
9814   LOG(INFO) << "Receive " << total_count << " message count in " << dialog_id << " with filter " << filter;
9815   if (total_count < 0) {
9816     LOG(ERROR) << "Receive total message count = " << total_count << " in " << dialog_id << " with filter " << filter;
9817     total_count = 0;
9818   }
9819 
9820   Dialog *d = get_dialog(dialog_id);
9821   CHECK(d != nullptr);
9822   CHECK(filter != MessageSearchFilter::Empty);
9823   CHECK(filter != MessageSearchFilter::UnreadMention);
9824   CHECK(filter != MessageSearchFilter::FailedToSend);
9825 
9826   auto &old_message_count = d->message_count_by_index[message_search_filter_index(filter)];
9827   if (old_message_count != total_count) {
9828     old_message_count = total_count;
9829     on_dialog_updated(dialog_id, "on_get_dialog_message_count");
9830   }
9831 
9832   if (total_count == 0) {
9833     auto &old_first_database_message_id = d->first_database_message_id_by_index[message_search_filter_index(filter)];
9834     if (old_first_database_message_id != MessageId::min()) {
9835       old_first_database_message_id = MessageId::min();
9836       on_dialog_updated(dialog_id, "on_get_dialog_message_count");
9837     }
9838     if (filter == MessageSearchFilter::Pinned) {
9839       set_dialog_last_pinned_message_id(d, MessageId());
9840     }
9841   }
9842   promise.set_value(std::move(total_count));
9843 }
9844 
on_get_messages_search_result(const string & query,int32 offset_date,DialogId offset_dialog_id,MessageId offset_message_id,int32 limit,MessageSearchFilter filter,int32 min_date,int32 max_date,int64 random_id,int32 total_count,vector<tl_object_ptr<telegram_api::Message>> && messages,Promise<Unit> && promise)9845 void MessagesManager::on_get_messages_search_result(const string &query, int32 offset_date, DialogId offset_dialog_id,
9846                                                     MessageId offset_message_id, int32 limit,
9847                                                     MessageSearchFilter filter, int32 min_date, int32 max_date,
9848                                                     int64 random_id, int32 total_count,
9849                                                     vector<tl_object_ptr<telegram_api::Message>> &&messages,
9850                                                     Promise<Unit> &&promise) {
9851   TRY_STATUS_PROMISE(promise, G()->close_status());
9852 
9853   LOG(INFO) << "Receive " << messages.size() << " found messages";
9854   auto it = found_messages_.find(random_id);
9855   CHECK(it != found_messages_.end());
9856 
9857   auto &result = it->second.second;
9858   CHECK(result.empty());
9859   for (auto &message : messages) {
9860     auto dialog_id = get_message_dialog_id(message);
9861     auto new_full_message_id = on_get_message(std::move(message), false, dialog_id.get_type() == DialogType::Channel,
9862                                               false, false, false, "search messages");
9863     if (new_full_message_id != FullMessageId()) {
9864       CHECK(dialog_id == new_full_message_id.get_dialog_id());
9865       result.push_back(new_full_message_id);
9866     } else {
9867       total_count--;
9868     }
9869   }
9870   if (total_count < static_cast<int32>(result.size())) {
9871     LOG(ERROR) << "Receive " << result.size() << " valid messages out of " << total_count << " in " << messages.size()
9872                << " messages";
9873     total_count = static_cast<int32>(result.size());
9874   }
9875   it->second.first = total_count;
9876   promise.set_value(Unit());
9877 }
9878 
on_failed_messages_search(int64 random_id)9879 void MessagesManager::on_failed_messages_search(int64 random_id) {
9880   auto it = found_messages_.find(random_id);
9881   CHECK(it != found_messages_.end());
9882   found_messages_.erase(it);
9883 }
9884 
on_get_scheduled_server_messages(DialogId dialog_id,uint32 generation,vector<tl_object_ptr<telegram_api::Message>> && messages,bool is_not_modified)9885 void MessagesManager::on_get_scheduled_server_messages(DialogId dialog_id, uint32 generation,
9886                                                        vector<tl_object_ptr<telegram_api::Message>> &&messages,
9887                                                        bool is_not_modified) {
9888   Dialog *d = get_dialog(dialog_id);
9889   CHECK(d != nullptr);
9890   if (generation < d->scheduled_messages_sync_generation) {
9891     LOG(INFO) << "Ignore scheduled messages with old generation " << generation << " instead of "
9892               << d->scheduled_messages_sync_generation << " in " << dialog_id;
9893     return;
9894   }
9895   d->scheduled_messages_sync_generation = generation;
9896 
9897   if (is_not_modified) {
9898     LOG(INFO) << "Scheduled messages are mot modified in " << dialog_id;
9899     return;
9900   }
9901 
9902   vector<MessageId> old_message_ids;
9903   find_old_messages(d->scheduled_messages.get(),
9904                     MessageId(ScheduledServerMessageId(), std::numeric_limits<int32>::max(), true), old_message_ids);
9905   std::unordered_map<ScheduledServerMessageId, MessageId, ScheduledServerMessageIdHash> old_server_message_ids;
9906   for (auto &message_id : old_message_ids) {
9907     if (message_id.is_scheduled_server()) {
9908       old_server_message_ids[message_id.get_scheduled_server_message_id()] = message_id;
9909     }
9910   }
9911 
9912   bool is_channel_message = dialog_id.get_type() == DialogType::Channel;
9913   bool has_scheduled_server_messages = false;
9914   for (auto &message : messages) {
9915     auto message_dialog_id = get_message_dialog_id(message);
9916     if (message_dialog_id != dialog_id) {
9917       LOG(ERROR) << "Receive " << get_message_id(message, true) << " in wrong " << message_dialog_id << " instead of "
9918                  << dialog_id << ": " << oneline(to_string(message));
9919       continue;
9920     }
9921 
9922     auto full_message_id = on_get_message(std::move(message), d->sent_scheduled_messages, is_channel_message, true,
9923                                           false, false, "on_get_scheduled_server_messages");
9924     auto message_id = full_message_id.get_message_id();
9925     if (message_id.is_valid_scheduled()) {
9926       CHECK(message_id.is_scheduled_server());
9927       old_server_message_ids.erase(message_id.get_scheduled_server_message_id());
9928       has_scheduled_server_messages = true;
9929     }
9930   }
9931   on_update_dialog_has_scheduled_server_messages(dialog_id, has_scheduled_server_messages);
9932 
9933   for (const auto &it : old_server_message_ids) {
9934     auto message_id = it.second;
9935     auto message = do_delete_scheduled_message(d, message_id, true, "on_get_scheduled_server_messages");
9936     CHECK(message != nullptr);
9937     send_update_delete_messages(dialog_id, {message->message_id.get()}, true, false);
9938   }
9939 
9940   send_update_chat_has_scheduled_messages(d, false);
9941 }
9942 
on_get_recent_locations(DialogId dialog_id,int32 limit,int32 total_count,vector<tl_object_ptr<telegram_api::Message>> && messages,Promise<td_api::object_ptr<td_api::messages>> && promise)9943 void MessagesManager::on_get_recent_locations(DialogId dialog_id, int32 limit, int32 total_count,
9944                                               vector<tl_object_ptr<telegram_api::Message>> &&messages,
9945                                               Promise<td_api::object_ptr<td_api::messages>> &&promise) {
9946   TRY_STATUS_PROMISE(promise, G()->close_status());
9947 
9948   LOG(INFO) << "Receive " << messages.size() << " recent locations in " << dialog_id;
9949   vector<MessageId> result;
9950   for (auto &message : messages) {
9951     auto new_full_message_id = on_get_message(std::move(message), false, dialog_id.get_type() == DialogType::Channel,
9952                                               false, false, false, "get recent locations");
9953     if (new_full_message_id != FullMessageId()) {
9954       if (new_full_message_id.get_dialog_id() != dialog_id) {
9955         LOG(ERROR) << "Receive " << new_full_message_id << " instead of a message in " << dialog_id;
9956         total_count--;
9957         continue;
9958       }
9959       auto m = get_message(new_full_message_id);
9960       CHECK(m != nullptr);
9961       if (m->content->get_type() != MessageContentType::LiveLocation) {
9962         LOG(ERROR) << "Receive a message of wrong type " << m->content->get_type() << " in on_get_recent_locations in "
9963                    << dialog_id;
9964         total_count--;
9965         continue;
9966       }
9967 
9968       result.push_back(m->message_id);
9969     } else {
9970       total_count--;
9971     }
9972   }
9973   if (total_count < static_cast<int32>(result.size())) {
9974     LOG(ERROR) << "Receive " << result.size() << " valid messages out of " << total_count << " in " << messages.size()
9975                << " messages";
9976     total_count = static_cast<int32>(result.size());
9977   }
9978   promise.set_value(get_messages_object(total_count, dialog_id, result, true, "on_get_recent_locations"));
9979 }
9980 
on_get_message_public_forwards(int32 total_count,vector<tl_object_ptr<telegram_api::Message>> && messages,Promise<td_api::object_ptr<td_api::foundMessages>> && promise)9981 void MessagesManager::on_get_message_public_forwards(int32 total_count,
9982                                                      vector<tl_object_ptr<telegram_api::Message>> &&messages,
9983                                                      Promise<td_api::object_ptr<td_api::foundMessages>> &&promise) {
9984   TRY_STATUS_PROMISE(promise, G()->close_status());
9985 
9986   LOG(INFO) << "Receive " << messages.size() << " forwarded messages";
9987   vector<td_api::object_ptr<td_api::message>> result;
9988   FullMessageId last_full_message_id;
9989   for (auto &message : messages) {
9990     auto dialog_id = get_message_dialog_id(message);
9991     auto new_full_message_id = on_get_message(std::move(message), false, dialog_id.get_type() == DialogType::Channel,
9992                                               false, false, false, "get message public forwards");
9993     if (new_full_message_id != FullMessageId()) {
9994       CHECK(dialog_id == new_full_message_id.get_dialog_id());
9995       result.push_back(get_message_object(new_full_message_id, "on_get_message_public_forwards"));
9996       CHECK(result.back() != nullptr);
9997       last_full_message_id = new_full_message_id;
9998     } else {
9999       total_count--;
10000     }
10001   }
10002   if (total_count < static_cast<int32>(result.size())) {
10003     LOG(ERROR) << "Receive " << result.size() << " valid messages out of " << total_count << " in " << messages.size()
10004                << " messages";
10005     total_count = static_cast<int32>(result.size());
10006   }
10007   string next_offset;
10008   if (!result.empty()) {
10009     auto m = get_message(last_full_message_id);
10010     CHECK(m != nullptr);
10011     next_offset = PSTRING() << m->date << "," << last_full_message_id.get_dialog_id().get() << ","
10012                             << m->message_id.get_server_message_id().get();
10013   }
10014 
10015   promise.set_value(td_api::make_object<td_api::foundMessages>(total_count, std::move(result), next_offset));
10016 }
10017 
delete_messages_from_updates(const vector<MessageId> & message_ids)10018 void MessagesManager::delete_messages_from_updates(const vector<MessageId> &message_ids) {
10019   std::unordered_map<DialogId, vector<int64>, DialogIdHash> deleted_message_ids;
10020   std::unordered_map<DialogId, bool, DialogIdHash> need_update_dialog_pos;
10021   for (auto message_id : message_ids) {
10022     if (!message_id.is_valid() || !message_id.is_server()) {
10023       LOG(ERROR) << "Incoming update tries to delete " << message_id;
10024       continue;
10025     }
10026 
10027     Dialog *d = get_dialog_by_message_id(message_id);
10028     if (d != nullptr) {
10029       auto message = delete_message(d, message_id, true, &need_update_dialog_pos[d->dialog_id], "updates");
10030       CHECK(message != nullptr);
10031       LOG_CHECK(message->message_id == message_id) << message_id << " " << message->message_id << " " << d->dialog_id;
10032       deleted_message_ids[d->dialog_id].push_back(message->message_id.get());
10033     }
10034     if (last_clear_history_message_id_to_dialog_id_.count(message_id)) {
10035       d = get_dialog(last_clear_history_message_id_to_dialog_id_[message_id]);
10036       CHECK(d != nullptr);
10037       auto message = delete_message(d, message_id, true, &need_update_dialog_pos[d->dialog_id], "updates");
10038       CHECK(message == nullptr);
10039     }
10040   }
10041   for (auto &it : need_update_dialog_pos) {
10042     if (it.second) {
10043       auto dialog_id = it.first;
10044       Dialog *d = get_dialog(dialog_id);
10045       CHECK(d != nullptr);
10046       send_update_chat_last_message(d, "delete_messages_from_updates");
10047     }
10048   }
10049   for (auto &it : deleted_message_ids) {
10050     auto dialog_id = it.first;
10051     send_update_delete_messages(dialog_id, std::move(it.second), true, false);
10052   }
10053 }
10054 
delete_dialog_messages(DialogId dialog_id,const vector<MessageId> & message_ids,bool from_updates,bool skip_update_for_not_found_messages,const char * source)10055 void MessagesManager::delete_dialog_messages(DialogId dialog_id, const vector<MessageId> &message_ids,
10056                                              bool from_updates, bool skip_update_for_not_found_messages,
10057                                              const char *source) {
10058   Dialog *d = get_dialog_force(dialog_id, "delete_dialog_messages");
10059   if (d == nullptr) {
10060     LOG(INFO) << "Ignore deleteChannelMessages for unknown " << dialog_id << " from " << source;
10061     CHECK(from_updates);
10062     CHECK(dialog_id.get_type() == DialogType::Channel);
10063     return;
10064   }
10065 
10066   vector<int64> deleted_message_ids;
10067   bool need_update_dialog_pos = false;
10068   for (auto message_id : message_ids) {
10069     CHECK(!message_id.is_scheduled());
10070     if (from_updates) {
10071       if (!message_id.is_valid() || (!message_id.is_server() && dialog_id.get_type() != DialogType::SecretChat)) {
10072         LOG(ERROR) << "Tried to delete " << message_id << " in " << dialog_id << " from " << source;
10073         continue;
10074       }
10075     } else {
10076       CHECK(message_id.is_valid());
10077     }
10078 
10079     bool was_already_deleted = d->deleted_message_ids.count(message_id) != 0;
10080     auto message = delete_message(d, message_id, true, &need_update_dialog_pos, source);
10081     if (message == nullptr) {
10082       if (!skip_update_for_not_found_messages && !was_already_deleted) {
10083         deleted_message_ids.push_back(message_id.get());
10084       }
10085     } else {
10086       deleted_message_ids.push_back(message->message_id.get());
10087     }
10088   }
10089   if (need_update_dialog_pos) {
10090     send_update_chat_last_message(d, source);
10091   }
10092   send_update_delete_messages(dialog_id, std::move(deleted_message_ids), true, false);
10093 }
10094 
update_dialog_pinned_messages_from_updates(DialogId dialog_id,const vector<MessageId> & message_ids,bool is_pin)10095 void MessagesManager::update_dialog_pinned_messages_from_updates(DialogId dialog_id,
10096                                                                  const vector<MessageId> &message_ids, bool is_pin) {
10097   Dialog *d = get_dialog_force(dialog_id, "update_dialog_pinned_messages_from_updates");
10098   if (d == nullptr) {
10099     LOG(INFO) << "Ignore updatePinnedMessages for unknown " << dialog_id;
10100     return;
10101   }
10102 
10103   for (auto message_id : message_ids) {
10104     if (!message_id.is_valid() || (!message_id.is_server() && dialog_id.get_type() != DialogType::SecretChat)) {
10105       LOG(ERROR) << "Incoming update tries to pin/unpin " << message_id << " in " << dialog_id;
10106       continue;
10107     }
10108 
10109     Message *m = get_message_force(d, message_id, "update_dialog_pinned_messages_from_updates");
10110     if (m != nullptr && update_message_is_pinned(d, m, is_pin, "update_dialog_pinned_messages_from_updates")) {
10111       on_message_changed(d, m, true, "update_dialog_pinned_messages_from_updates");
10112     }
10113   }
10114 }
10115 
update_message_is_pinned(Dialog * d,Message * m,bool is_pinned,const char * source)10116 bool MessagesManager::update_message_is_pinned(Dialog *d, Message *m, bool is_pinned, const char *source) {
10117   CHECK(m != nullptr);
10118   CHECK(!m->message_id.is_scheduled());
10119   if (m->is_pinned == is_pinned) {
10120     return false;
10121   }
10122 
10123   LOG(INFO) << "Update message is_pinned of " << m->message_id << " in " << d->dialog_id << " to " << is_pinned
10124             << " from " << source;
10125   auto old_index_mask = get_message_index_mask(d->dialog_id, m);
10126   m->is_pinned = is_pinned;
10127   auto new_index_mask = get_message_index_mask(d->dialog_id, m);
10128   update_message_count_by_index(d, -1, old_index_mask & ~new_index_mask);
10129   update_message_count_by_index(d, +1, new_index_mask & ~old_index_mask);
10130 
10131   send_closure(G()->td(), &Td::send_update,
10132                make_tl_object<td_api::updateMessageIsPinned>(d->dialog_id.get(), m->message_id.get(), is_pinned));
10133   if (is_pinned) {
10134     if (d->is_last_pinned_message_id_inited && m->message_id > d->last_pinned_message_id) {
10135       set_dialog_last_pinned_message_id(d, m->message_id);
10136     }
10137   } else {
10138     if (d->is_last_pinned_message_id_inited && m->message_id == d->last_pinned_message_id) {
10139       if (d->message_count_by_index[message_search_filter_index(MessageSearchFilter::Pinned)] == 0) {
10140         set_dialog_last_pinned_message_id(d, MessageId());
10141       } else {
10142         drop_dialog_last_pinned_message_id(d);
10143       }
10144     }
10145   }
10146   return true;
10147 }
10148 
get_message_search_text(const Message * m) const10149 string MessagesManager::get_message_search_text(const Message *m) const {
10150   if (m->is_content_secret) {
10151     return string();
10152   }
10153   return get_message_content_search_text(td_, m->content.get());
10154 }
10155 
can_forward_message(DialogId from_dialog_id,const Message * m)10156 bool MessagesManager::can_forward_message(DialogId from_dialog_id, const Message *m) {
10157   if (m == nullptr) {
10158     return false;
10159   }
10160   if (m->ttl > 0) {
10161     return false;
10162   }
10163   if (m->message_id.is_scheduled()) {
10164     return false;
10165   }
10166   switch (from_dialog_id.get_type()) {
10167     case DialogType::User:
10168     case DialogType::Chat:
10169     case DialogType::Channel:
10170       // ok
10171       break;
10172     case DialogType::SecretChat:
10173       return false;
10174     case DialogType::None:
10175     default:
10176       UNREACHABLE();
10177       return false;
10178   }
10179 
10180   return can_forward_message_content(m->content.get());
10181 }
10182 
can_save_message(DialogId dialog_id,const Message * m) const10183 bool MessagesManager::can_save_message(DialogId dialog_id, const Message *m) const {
10184   if (m == nullptr || m->noforwards || m->is_content_secret) {
10185     return false;
10186   }
10187   return !get_dialog_has_protected_content(dialog_id);
10188 }
10189 
can_get_message_statistics(FullMessageId full_message_id)10190 bool MessagesManager::can_get_message_statistics(FullMessageId full_message_id) {
10191   return can_get_message_statistics(full_message_id.get_dialog_id(),
10192                                     get_message_force(full_message_id, "can_get_message_statistics"));
10193 }
10194 
can_get_message_statistics(DialogId dialog_id,const Message * m) const10195 bool MessagesManager::can_get_message_statistics(DialogId dialog_id, const Message *m) const {
10196   if (td_->auth_manager_->is_bot()) {
10197     return false;
10198   }
10199   if (m == nullptr || m->message_id.is_scheduled() || !m->message_id.is_server() || m->view_count == 0 ||
10200       m->had_forward_info || (m->forward_info != nullptr && m->forward_info->message_id.is_valid())) {
10201     return false;
10202   }
10203   return td_->contacts_manager_->can_get_channel_message_statistics(dialog_id);
10204 }
10205 
can_delete_channel_message(const DialogParticipantStatus & status,const Message * m,bool is_bot)10206 bool MessagesManager::can_delete_channel_message(const DialogParticipantStatus &status, const Message *m, bool is_bot) {
10207   if (m == nullptr) {
10208     return true;
10209   }
10210   if (m->message_id.is_local() || m->message_id.is_yet_unsent()) {
10211     return true;
10212   }
10213   if (m->message_id.is_scheduled()) {
10214     if (m->is_channel_post) {
10215       return status.can_post_messages();
10216     }
10217     return true;
10218   }
10219 
10220   if (is_bot && G()->unix_time_cached() >= m->date + 2 * 86400) {
10221     // bots can't delete messages older than 2 days
10222     return false;
10223   }
10224 
10225   CHECK(m->message_id.is_server());
10226   if (m->message_id.get_server_message_id().get() == 1) {
10227     return false;
10228   }
10229   auto content_type = m->content->get_type();
10230   if (content_type == MessageContentType::ChannelMigrateFrom || content_type == MessageContentType::ChannelCreate) {
10231     return false;
10232   }
10233 
10234   if (status.can_delete_messages()) {
10235     return true;
10236   }
10237 
10238   if (!m->is_outgoing) {
10239     return false;
10240   }
10241 
10242   if (m->is_channel_post || is_service_message_content(content_type)) {
10243     return status.can_post_messages();
10244   }
10245 
10246   return true;
10247 }
10248 
can_delete_message(DialogId dialog_id,const Message * m) const10249 bool MessagesManager::can_delete_message(DialogId dialog_id, const Message *m) const {
10250   if (m == nullptr) {
10251     return true;
10252   }
10253   if (m->message_id.is_local() || m->message_id.is_yet_unsent()) {
10254     return true;
10255   }
10256   switch (dialog_id.get_type()) {
10257     case DialogType::User:
10258       return true;
10259     case DialogType::Chat:
10260       return true;
10261     case DialogType::Channel: {
10262       auto dialog_status = td_->contacts_manager_->get_channel_permissions(dialog_id.get_channel_id());
10263       return can_delete_channel_message(dialog_status, m, td_->auth_manager_->is_bot());
10264     }
10265     case DialogType::SecretChat:
10266       return true;
10267     case DialogType::None:
10268     default:
10269       UNREACHABLE();
10270       return false;
10271   }
10272 }
10273 
can_revoke_message(DialogId dialog_id,const Message * m) const10274 bool MessagesManager::can_revoke_message(DialogId dialog_id, const Message *m) const {
10275   if (m == nullptr) {
10276     return true;
10277   }
10278   if (m->message_id.is_local()) {
10279     return false;
10280   }
10281   if (dialog_id == get_my_dialog_id()) {
10282     return false;
10283   }
10284   if (m->message_id.is_scheduled()) {
10285     return false;
10286   }
10287   if (m->message_id.is_yet_unsent()) {
10288     return true;
10289   }
10290   CHECK(m->message_id.is_server());
10291 
10292   const int32 DEFAULT_REVOKE_TIME_LIMIT = td_->auth_manager_->is_bot() ? 2 * 86400 : std::numeric_limits<int32>::max();
10293   auto content_type = m->content->get_type();
10294   switch (dialog_id.get_type()) {
10295     case DialogType::User: {
10296       bool can_revoke_incoming = G()->shared_config().get_option_boolean("revoke_pm_inbox", true);
10297       int64 revoke_time_limit =
10298           G()->shared_config().get_option_integer("revoke_pm_time_limit", DEFAULT_REVOKE_TIME_LIMIT);
10299 
10300       if (G()->unix_time_cached() - m->date < 86400 && content_type == MessageContentType::Dice) {
10301         return false;
10302       }
10303       return ((m->is_outgoing && !is_service_message_content(content_type)) ||
10304               (can_revoke_incoming && content_type != MessageContentType::ScreenshotTaken)) &&
10305              G()->unix_time_cached() - m->date <= revoke_time_limit;
10306     }
10307     case DialogType::Chat: {
10308       bool is_appointed_administrator =
10309           td_->contacts_manager_->is_appointed_chat_administrator(dialog_id.get_chat_id());
10310       int64 revoke_time_limit = G()->shared_config().get_option_integer("revoke_time_limit", DEFAULT_REVOKE_TIME_LIMIT);
10311 
10312       return ((m->is_outgoing && !is_service_message_content(content_type)) || is_appointed_administrator) &&
10313              G()->unix_time_cached() - m->date <= revoke_time_limit;
10314     }
10315     case DialogType::Channel:
10316       return true;  // any server message that can be deleted will be deleted for all participants
10317     case DialogType::SecretChat:
10318       // all non-service messages will be deleted for everyone if secret chat is active
10319       return td_->contacts_manager_->get_secret_chat_state(dialog_id.get_secret_chat_id()) == SecretChatState::Active &&
10320              !is_service_message_content(content_type);
10321     case DialogType::None:
10322     default:
10323       UNREACHABLE();
10324       return false;
10325   }
10326 }
10327 
delete_messages(DialogId dialog_id,const vector<MessageId> & input_message_ids,bool revoke,Promise<Unit> && promise)10328 void MessagesManager::delete_messages(DialogId dialog_id, const vector<MessageId> &input_message_ids, bool revoke,
10329                                       Promise<Unit> &&promise) {
10330   TRY_STATUS_PROMISE(promise, G()->close_status());
10331   Dialog *d = get_dialog_force(dialog_id, "delete_messages");
10332   if (d == nullptr) {
10333     return promise.set_error(Status::Error(400, "Chat is not found"));
10334   }
10335 
10336   if (input_message_ids.empty()) {
10337     return promise.set_value(Unit());
10338   }
10339 
10340   auto dialog_type = dialog_id.get_type();
10341   bool is_secret = dialog_type == DialogType::SecretChat;
10342 
10343   vector<MessageId> message_ids;
10344   message_ids.reserve(input_message_ids.size());
10345   vector<MessageId> deleted_server_message_ids;
10346 
10347   vector<MessageId> deleted_scheduled_server_message_ids;
10348   for (auto message_id : input_message_ids) {
10349     if (!message_id.is_valid() && !message_id.is_valid_scheduled()) {
10350       return promise.set_error(Status::Error(400, "Invalid message identifier"));
10351     }
10352 
10353     message_id = get_persistent_message_id(d, message_id);
10354     message_ids.push_back(message_id);
10355     auto m = get_message_force(d, message_id, "delete_messages");
10356     if (m != nullptr) {
10357       if (m->message_id.is_scheduled()) {
10358         if (m->message_id.is_scheduled_server()) {
10359           deleted_scheduled_server_message_ids.push_back(m->message_id);
10360         }
10361       } else {
10362         if (m->message_id.is_server() || is_secret) {
10363           deleted_server_message_ids.push_back(m->message_id);
10364         }
10365       }
10366     }
10367   }
10368 
10369   bool is_bot = td_->auth_manager_->is_bot();
10370   for (auto message_id : message_ids) {
10371     auto m = get_message(d, message_id);
10372     if (!can_delete_message(dialog_id, m)) {
10373       return promise.set_error(Status::Error(400, "Message can't be deleted"));
10374     }
10375     if (is_bot && !message_id.is_scheduled() && message_id.is_server() && !can_revoke_message(dialog_id, m)) {
10376       return promise.set_error(Status::Error(400, "Message can't be deleted for everyone"));
10377     }
10378   }
10379 
10380   MultiPromiseActorSafe mpas{"DeleteMessagesMultiPromiseActor"};
10381   mpas.add_promise(std::move(promise));
10382 
10383   auto lock = mpas.get_promise();
10384   delete_messages_on_server(dialog_id, std::move(deleted_server_message_ids), revoke, 0, mpas.get_promise());
10385   delete_scheduled_messages_on_server(dialog_id, std::move(deleted_scheduled_server_message_ids), 0,
10386                                       mpas.get_promise());
10387   lock.set_value(Unit());
10388 
10389   bool need_update_dialog_pos = false;
10390   bool need_update_chat_has_scheduled_messages = false;
10391   vector<int64> deleted_message_ids;
10392   for (auto message_id : message_ids) {
10393     auto m = delete_message(d, message_id, true, &need_update_dialog_pos, DELETE_MESSAGE_USER_REQUEST_SOURCE);
10394     if (m == nullptr) {
10395       LOG(INFO) << "Can't delete " << message_id << " because it is not found";
10396     } else {
10397       need_update_chat_has_scheduled_messages |= m->message_id.is_scheduled();
10398       deleted_message_ids.push_back(m->message_id.get());
10399     }
10400   }
10401 
10402   if (need_update_dialog_pos) {
10403     send_update_chat_last_message(d, "delete_messages");
10404   }
10405   send_update_delete_messages(dialog_id, std::move(deleted_message_ids), true, false);
10406 
10407   if (need_update_chat_has_scheduled_messages) {
10408     send_update_chat_has_scheduled_messages(d, true);
10409   }
10410 }
10411 
erase_delete_messages_log_event(uint64 log_event_id)10412 void MessagesManager::erase_delete_messages_log_event(uint64 log_event_id) {
10413   if (!G()->close_flag()) {
10414     binlog_erase(G()->td_db()->get_binlog(), log_event_id);
10415   }
10416 }
10417 
delete_sent_message_on_server(DialogId dialog_id,MessageId message_id)10418 void MessagesManager::delete_sent_message_on_server(DialogId dialog_id, MessageId message_id) {
10419   // being sent message was deleted by the user or is in an inaccessible channel
10420   // don't need to send an update to the user, because the message has already been deleted
10421   if (!have_input_peer(dialog_id, AccessRights::Read)) {
10422     LOG(INFO) << "Ignore sent " << message_id << " in inaccessible " << dialog_id;
10423     return;
10424   }
10425 
10426   LOG(INFO) << "Delete already deleted sent " << message_id << " in " << dialog_id << " from server";
10427   Dialog *d = get_dialog(dialog_id);
10428   CHECK(d != nullptr);
10429   if (get_message_force(d, message_id, "delete_sent_message_on_server") != nullptr) {
10430     delete_messages(dialog_id, {message_id}, true, Auto());
10431   } else {
10432     if (message_id.is_valid()) {
10433       CHECK(message_id.is_server());
10434       delete_messages_on_server(dialog_id, {message_id}, true, 0, Auto());
10435     } else {
10436       CHECK(message_id.is_scheduled_server());
10437       delete_scheduled_messages_on_server(dialog_id, {message_id}, 0, Auto());
10438     }
10439 
10440     bool need_update_dialog_pos = false;
10441     auto m = delete_message(d, message_id, true, &need_update_dialog_pos, "delete_sent_message_on_server");
10442     CHECK(m == nullptr);
10443     CHECK(need_update_dialog_pos == false);
10444   }
10445 }
10446 
10447 class MessagesManager::DeleteMessagesOnServerLogEvent {
10448  public:
10449   DialogId dialog_id_;
10450   vector<MessageId> message_ids_;
10451   bool revoke_;
10452 
10453   template <class StorerT>
store(StorerT & storer) const10454   void store(StorerT &storer) const {
10455     BEGIN_STORE_FLAGS();
10456     STORE_FLAG(revoke_);
10457     END_STORE_FLAGS();
10458 
10459     td::store(dialog_id_, storer);
10460     td::store(message_ids_, storer);
10461   }
10462 
10463   template <class ParserT>
parse(ParserT & parser)10464   void parse(ParserT &parser) {
10465     BEGIN_PARSE_FLAGS();
10466     PARSE_FLAG(revoke_);
10467     END_PARSE_FLAGS();
10468 
10469     td::parse(dialog_id_, parser);
10470     td::parse(message_ids_, parser);
10471   }
10472 };
10473 
save_delete_messages_on_server_log_event(DialogId dialog_id,const vector<MessageId> & message_ids,bool revoke)10474 uint64 MessagesManager::save_delete_messages_on_server_log_event(DialogId dialog_id,
10475                                                                  const vector<MessageId> &message_ids, bool revoke) {
10476   DeleteMessagesOnServerLogEvent log_event{dialog_id, message_ids, revoke};
10477   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::DeleteMessagesOnServer,
10478                     get_log_event_storer(log_event));
10479 }
10480 
delete_messages_on_server(DialogId dialog_id,vector<MessageId> message_ids,bool revoke,uint64 log_event_id,Promise<Unit> && promise)10481 void MessagesManager::delete_messages_on_server(DialogId dialog_id, vector<MessageId> message_ids, bool revoke,
10482                                                 uint64 log_event_id, Promise<Unit> &&promise) {
10483   if (message_ids.empty()) {
10484     return promise.set_value(Unit());
10485   }
10486   LOG(INFO) << (revoke ? "Revoke " : "Delete ") << format::as_array(message_ids) << " in " << dialog_id
10487             << " from server";
10488 
10489   if (log_event_id == 0 && G()->parameters().use_message_db) {
10490     log_event_id = save_delete_messages_on_server_log_event(dialog_id, message_ids, revoke);
10491   }
10492 
10493   MultiPromiseActorSafe mpas{"DeleteMessagesOnServerMultiPromiseActor"};
10494   mpas.add_promise(std::move(promise));
10495   if (log_event_id != 0) {
10496     mpas.add_promise(PromiseCreator::lambda([actor_id = actor_id(this), log_event_id](Unit) {
10497       send_closure(actor_id, &MessagesManager::erase_delete_messages_log_event, log_event_id);
10498     }));
10499   }
10500   mpas.set_ignore_errors(true);
10501   auto lock = mpas.get_promise();
10502   auto dialog_type = dialog_id.get_type();
10503   switch (dialog_type) {
10504     case DialogType::User:
10505     case DialogType::Chat:
10506     case DialogType::Channel: {
10507       auto server_message_ids = MessagesManager::get_server_message_ids(message_ids);
10508       const size_t MAX_SLICE_SIZE = 100;  // server side limit
10509       for (size_t i = 0; i < server_message_ids.size(); i += MAX_SLICE_SIZE) {
10510         auto end_i = i + MAX_SLICE_SIZE;
10511         auto end = end_i < server_message_ids.size() ? server_message_ids.begin() + end_i : server_message_ids.end();
10512         if (dialog_type != DialogType::Channel) {
10513           td_->create_handler<DeleteMessagesQuery>(mpas.get_promise())
10514               ->send(dialog_id, {server_message_ids.begin() + i, end}, revoke);
10515         } else {
10516           td_->create_handler<DeleteChannelMessagesQuery>(mpas.get_promise())
10517               ->send(dialog_id.get_channel_id(), {server_message_ids.begin() + i, end});
10518         }
10519       }
10520       break;
10521     }
10522     case DialogType::SecretChat: {
10523       vector<int64> random_ids;
10524       auto d = get_dialog_force(dialog_id, "delete_messages_on_server");
10525       CHECK(d != nullptr);
10526       for (auto &message_id : message_ids) {
10527         auto *m = get_message(d, message_id);
10528         if (m != nullptr) {
10529           random_ids.push_back(m->random_id);
10530         }
10531       }
10532       if (!random_ids.empty()) {
10533         send_closure(G()->secret_chats_manager(), &SecretChatsManager::delete_messages, dialog_id.get_secret_chat_id(),
10534                      std::move(random_ids), mpas.get_promise());
10535       }
10536       break;
10537     }
10538     case DialogType::None:
10539     default:
10540       UNREACHABLE();
10541   }
10542   lock.set_value(Unit());
10543 }
10544 
10545 class MessagesManager::DeleteScheduledMessagesOnServerLogEvent {
10546  public:
10547   DialogId dialog_id_;
10548   vector<MessageId> message_ids_;
10549 
10550   template <class StorerT>
store(StorerT & storer) const10551   void store(StorerT &storer) const {
10552     td::store(dialog_id_, storer);
10553     td::store(message_ids_, storer);
10554   }
10555 
10556   template <class ParserT>
parse(ParserT & parser)10557   void parse(ParserT &parser) {
10558     td::parse(dialog_id_, parser);
10559     td::parse(message_ids_, parser);
10560   }
10561 };
10562 
save_delete_scheduled_messages_on_server_log_event(DialogId dialog_id,const vector<MessageId> & message_ids)10563 uint64 MessagesManager::save_delete_scheduled_messages_on_server_log_event(DialogId dialog_id,
10564                                                                            const vector<MessageId> &message_ids) {
10565   DeleteScheduledMessagesOnServerLogEvent log_event{dialog_id, message_ids};
10566   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::DeleteScheduledMessagesOnServer,
10567                     get_log_event_storer(log_event));
10568 }
10569 
delete_scheduled_messages_on_server(DialogId dialog_id,vector<MessageId> message_ids,uint64 log_event_id,Promise<Unit> && promise)10570 void MessagesManager::delete_scheduled_messages_on_server(DialogId dialog_id, vector<MessageId> message_ids,
10571                                                           uint64 log_event_id, Promise<Unit> &&promise) {
10572   if (message_ids.empty()) {
10573     return promise.set_value(Unit());
10574   }
10575   LOG(INFO) << "Delete " << format::as_array(message_ids) << " in " << dialog_id << " from server";
10576 
10577   if (log_event_id == 0 && G()->parameters().use_message_db) {
10578     log_event_id = save_delete_scheduled_messages_on_server_log_event(dialog_id, message_ids);
10579   }
10580 
10581   auto new_promise = get_erase_log_event_promise(log_event_id, std::move(promise));
10582   promise = std::move(new_promise);  // to prevent self-move
10583 
10584   td_->create_handler<DeleteScheduledMessagesQuery>(std::move(promise))->send(dialog_id, std::move(message_ids));
10585 }
10586 
delete_dialog_history(DialogId dialog_id,bool remove_from_dialog_list,bool revoke,Promise<Unit> && promise)10587 void MessagesManager::delete_dialog_history(DialogId dialog_id, bool remove_from_dialog_list, bool revoke,
10588                                             Promise<Unit> &&promise) {
10589   LOG(INFO) << "Receive deleteChatHistory request to delete all messages in " << dialog_id
10590             << ", remove_from_chat_list is " << remove_from_dialog_list << ", revoke is " << revoke;
10591 
10592   Dialog *d = get_dialog_force(dialog_id, "delete_dialog_history");
10593   if (d == nullptr) {
10594     return promise.set_error(Status::Error(400, "Chat not found"));
10595   }
10596 
10597   if (!have_input_peer(dialog_id, AccessRights::Read)) {
10598     return promise.set_error(Status::Error(400, "Chat info not found"));
10599   }
10600 
10601   if (is_dialog_sponsored(d)) {
10602     auto chat_source = sponsored_dialog_source_.get_chat_source_object();
10603     if (chat_source == nullptr || chat_source->get_id() != td_api::chatSourcePublicServiceAnnouncement::ID) {
10604       return promise.set_error(Status::Error(400, "Can't delete the chat"));
10605     }
10606     if (!remove_from_dialog_list) {
10607       return promise.set_error(
10608           Status::Error(400, "Can't delete only chat history without removing the chat from the chat list"));
10609     }
10610 
10611     removed_sponsored_dialog_id_ = dialog_id;
10612     remove_sponsored_dialog();
10613 
10614     td_->create_handler<HidePromoDataQuery>()->send(dialog_id);
10615     promise.set_value(Unit());
10616     return;
10617   }
10618 
10619   auto dialog_type = dialog_id.get_type();
10620   switch (dialog_type) {
10621     case DialogType::User:
10622     case DialogType::Chat:
10623       // ok
10624       break;
10625     case DialogType::Channel:
10626       if (is_broadcast_channel(dialog_id)) {
10627         return promise.set_error(Status::Error(400, "Can't delete chat history in a channel"));
10628       }
10629       if (td_->contacts_manager_->is_channel_public(dialog_id.get_channel_id())) {
10630         return promise.set_error(Status::Error(400, "Can't delete chat history in a public supergroup"));
10631       }
10632       break;
10633     case DialogType::SecretChat:
10634       // ok
10635       break;
10636     case DialogType::None:
10637     default:
10638       UNREACHABLE();
10639       break;
10640   }
10641 
10642   auto last_new_message_id = d->last_new_message_id;
10643   if (dialog_type != DialogType::SecretChat && last_new_message_id == MessageId()) {
10644     // TODO get dialog from the server and delete history from last message identifier
10645   }
10646 
10647   bool allow_error = d->messages == nullptr;
10648   auto old_order = d->order;
10649 
10650   delete_all_dialog_messages(d, remove_from_dialog_list, true);
10651 
10652   if (last_new_message_id.is_valid() && last_new_message_id == d->max_unavailable_message_id && !revoke &&
10653       !(old_order != DEFAULT_ORDER && remove_from_dialog_list)) {
10654     // history has already been cleared, nothing to do
10655     promise.set_value(Unit());
10656     return;
10657   }
10658 
10659   set_dialog_max_unavailable_message_id(dialog_id, last_new_message_id, false, "delete_dialog_history");
10660 
10661   delete_dialog_history_on_server(dialog_id, last_new_message_id, remove_from_dialog_list, revoke, allow_error, 0,
10662                                   std::move(promise));
10663 }
10664 
10665 class MessagesManager::DeleteDialogHistoryOnServerLogEvent {
10666  public:
10667   DialogId dialog_id_;
10668   MessageId max_message_id_;
10669   bool remove_from_dialog_list_;
10670   bool revoke_;
10671 
10672   template <class StorerT>
store(StorerT & storer) const10673   void store(StorerT &storer) const {
10674     BEGIN_STORE_FLAGS();
10675     STORE_FLAG(remove_from_dialog_list_);
10676     STORE_FLAG(revoke_);
10677     END_STORE_FLAGS();
10678 
10679     td::store(dialog_id_, storer);
10680     td::store(max_message_id_, storer);
10681   }
10682 
10683   template <class ParserT>
parse(ParserT & parser)10684   void parse(ParserT &parser) {
10685     BEGIN_PARSE_FLAGS();
10686     PARSE_FLAG(remove_from_dialog_list_);
10687     PARSE_FLAG(revoke_);
10688     END_PARSE_FLAGS();
10689 
10690     td::parse(dialog_id_, parser);
10691     td::parse(max_message_id_, parser);
10692   }
10693 };
10694 
save_delete_dialog_history_on_server_log_event(DialogId dialog_id,MessageId max_message_id,bool remove_from_dialog_list,bool revoke)10695 uint64 MessagesManager::save_delete_dialog_history_on_server_log_event(DialogId dialog_id, MessageId max_message_id,
10696                                                                        bool remove_from_dialog_list, bool revoke) {
10697   DeleteDialogHistoryOnServerLogEvent log_event{dialog_id, max_message_id, remove_from_dialog_list, revoke};
10698   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::DeleteDialogHistoryOnServer,
10699                     get_log_event_storer(log_event));
10700 }
10701 
delete_dialog_history_on_server(DialogId dialog_id,MessageId max_message_id,bool remove_from_dialog_list,bool revoke,bool allow_error,uint64 log_event_id,Promise<Unit> && promise)10702 void MessagesManager::delete_dialog_history_on_server(DialogId dialog_id, MessageId max_message_id,
10703                                                       bool remove_from_dialog_list, bool revoke, bool allow_error,
10704                                                       uint64 log_event_id, Promise<Unit> &&promise) {
10705   LOG(INFO) << "Delete history in " << dialog_id << " up to " << max_message_id << " from server";
10706 
10707   if (log_event_id == 0 && G()->parameters().use_message_db) {
10708     log_event_id =
10709         save_delete_dialog_history_on_server_log_event(dialog_id, max_message_id, remove_from_dialog_list, revoke);
10710   }
10711 
10712   auto new_promise = get_erase_log_event_promise(log_event_id, std::move(promise));
10713   promise = std::move(new_promise);  // to prevent self-move
10714 
10715   switch (dialog_id.get_type()) {
10716     case DialogType::User:
10717     case DialogType::Chat: {
10718       AffectedHistoryQuery query = [td = td_, max_message_id, remove_from_dialog_list, revoke](
10719                                        DialogId dialog_id, Promise<AffectedHistory> &&query_promise) {
10720         td->create_handler<DeleteHistoryQuery>(std::move(query_promise))
10721             ->send(dialog_id, max_message_id, remove_from_dialog_list, revoke);
10722       };
10723       run_affected_history_query_until_complete(dialog_id, std::move(query), false, std::move(promise));
10724       break;
10725     }
10726     case DialogType::Channel:
10727       td_->create_handler<DeleteChannelHistoryQuery>(std::move(promise))
10728           ->send(dialog_id.get_channel_id(), max_message_id, allow_error);
10729       break;
10730     case DialogType::SecretChat:
10731       send_closure(G()->secret_chats_manager(), &SecretChatsManager::delete_all_messages,
10732                    dialog_id.get_secret_chat_id(), std::move(promise));
10733       break;
10734     case DialogType::None:
10735     default:
10736       UNREACHABLE();
10737       break;
10738   }
10739 }
10740 
delete_all_call_messages(bool revoke,Promise<Unit> && promise)10741 void MessagesManager::delete_all_call_messages(bool revoke, Promise<Unit> &&promise) {
10742   delete_all_call_messages_on_server(revoke, 0, std::move(promise));
10743 }
10744 
10745 class MessagesManager::DeleteAllCallMessagesOnServerLogEvent {
10746  public:
10747   bool revoke_;
10748 
10749   template <class StorerT>
store(StorerT & storer) const10750   void store(StorerT &storer) const {
10751     BEGIN_STORE_FLAGS();
10752     STORE_FLAG(revoke_);
10753     END_STORE_FLAGS();
10754   }
10755 
10756   template <class ParserT>
parse(ParserT & parser)10757   void parse(ParserT &parser) {
10758     BEGIN_PARSE_FLAGS();
10759     PARSE_FLAG(revoke_);
10760     END_PARSE_FLAGS();
10761   }
10762 };
10763 
save_delete_all_call_messages_on_server_log_event(bool revoke)10764 uint64 MessagesManager::save_delete_all_call_messages_on_server_log_event(bool revoke) {
10765   DeleteAllCallMessagesOnServerLogEvent log_event{revoke};
10766   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::DeleteAllCallMessagesOnServer,
10767                     get_log_event_storer(log_event));
10768 }
10769 
delete_all_call_messages_on_server(bool revoke,uint64 log_event_id,Promise<Unit> && promise)10770 void MessagesManager::delete_all_call_messages_on_server(bool revoke, uint64 log_event_id, Promise<Unit> &&promise) {
10771   if (log_event_id == 0) {
10772     log_event_id = save_delete_all_call_messages_on_server_log_event(revoke);
10773   }
10774 
10775   AffectedHistoryQuery query = [td = td_, revoke](DialogId /*dialog_id*/, Promise<AffectedHistory> &&query_promise) {
10776     td->create_handler<DeletePhoneCallHistoryQuery>(std::move(query_promise))->send(revoke);
10777   };
10778   run_affected_history_query_until_complete(DialogId(), std::move(query), false,
10779                                             get_erase_log_event_promise(log_event_id, std::move(promise)));
10780 }
10781 
find_messages(const Message * m,vector<MessageId> & message_ids,const std::function<bool (const Message *)> & condition)10782 void MessagesManager::find_messages(const Message *m, vector<MessageId> &message_ids,
10783                                     const std::function<bool(const Message *)> &condition) {
10784   if (m == nullptr) {
10785     return;
10786   }
10787 
10788   find_messages(m->left.get(), message_ids, condition);
10789 
10790   if (condition(m)) {
10791     message_ids.push_back(m->message_id);
10792   }
10793 
10794   find_messages(m->right.get(), message_ids, condition);
10795 }
10796 
find_old_messages(const Message * m,MessageId max_message_id,vector<MessageId> & message_ids)10797 void MessagesManager::find_old_messages(const Message *m, MessageId max_message_id, vector<MessageId> &message_ids) {
10798   if (m == nullptr) {
10799     return;
10800   }
10801 
10802   find_old_messages(m->left.get(), max_message_id, message_ids);
10803 
10804   if (m->message_id <= max_message_id) {
10805     message_ids.push_back(m->message_id);
10806 
10807     find_old_messages(m->right.get(), max_message_id, message_ids);
10808   }
10809 }
10810 
find_newer_messages(const Message * m,MessageId min_message_id,vector<MessageId> & message_ids)10811 void MessagesManager::find_newer_messages(const Message *m, MessageId min_message_id, vector<MessageId> &message_ids) {
10812   if (m == nullptr) {
10813     return;
10814   }
10815 
10816   if (m->message_id > min_message_id) {
10817     find_newer_messages(m->left.get(), min_message_id, message_ids);
10818 
10819     message_ids.push_back(m->message_id);
10820   }
10821 
10822   find_newer_messages(m->right.get(), min_message_id, message_ids);
10823 }
10824 
find_unloadable_messages(const Dialog * d,int32 unload_before_date,const Message * m,vector<MessageId> & message_ids,int32 & left_to_unload) const10825 void MessagesManager::find_unloadable_messages(const Dialog *d, int32 unload_before_date, const Message *m,
10826                                                vector<MessageId> &message_ids, int32 &left_to_unload) const {
10827   if (m == nullptr) {
10828     return;
10829   }
10830 
10831   find_unloadable_messages(d, unload_before_date, m->left.get(), message_ids, left_to_unload);
10832 
10833   if (can_unload_message(d, m)) {
10834     if (m->last_access_date <= unload_before_date) {
10835       message_ids.push_back(m->message_id);
10836     } else {
10837       left_to_unload++;
10838     }
10839   }
10840 
10841   find_unloadable_messages(d, unload_before_date, m->right.get(), message_ids, left_to_unload);
10842 }
10843 
delete_dialog_messages_by_sender(DialogId dialog_id,DialogId sender_dialog_id,Promise<Unit> && promise)10844 void MessagesManager::delete_dialog_messages_by_sender(DialogId dialog_id, DialogId sender_dialog_id,
10845                                                        Promise<Unit> &&promise) {
10846   bool is_bot = td_->auth_manager_->is_bot();
10847   CHECK(!is_bot);
10848 
10849   Dialog *d = get_dialog_force(dialog_id, "delete_dialog_messages_by_sender");
10850   if (d == nullptr) {
10851     return promise.set_error(Status::Error(400, "Chat not found"));
10852   }
10853 
10854   if (!have_input_peer(dialog_id, AccessRights::Write)) {
10855     return promise.set_error(Status::Error(400, "Not enough rights"));
10856   }
10857 
10858   if (!have_input_peer(sender_dialog_id, AccessRights::Know)) {
10859     return promise.set_error(Status::Error(400, "Message sender not found"));
10860   }
10861 
10862   ChannelId channel_id;
10863   DialogParticipantStatus channel_status = DialogParticipantStatus::Left();
10864   switch (dialog_id.get_type()) {
10865     case DialogType::User:
10866     case DialogType::Chat:
10867     case DialogType::SecretChat:
10868       return promise.set_error(
10869           Status::Error(400, "All messages from a sender can be deleted only in supergroup chats"));
10870     case DialogType::Channel: {
10871       channel_id = dialog_id.get_channel_id();
10872       auto channel_type = td_->contacts_manager_->get_channel_type(channel_id);
10873       if (channel_type != ContactsManager::ChannelType::Megagroup) {
10874         return promise.set_error(Status::Error(400, "The method is available only for supergroup chats"));
10875       }
10876       channel_status = td_->contacts_manager_->get_channel_permissions(channel_id);
10877       if (!channel_status.can_delete_messages()) {
10878         return promise.set_error(Status::Error(400, "Need delete messages administator right in the supergroup chat"));
10879       }
10880       channel_id = dialog_id.get_channel_id();
10881       break;
10882     }
10883     case DialogType::None:
10884     default:
10885       UNREACHABLE();
10886       break;
10887   }
10888   CHECK(channel_id.is_valid());
10889 
10890   if (sender_dialog_id.get_type() == DialogType::SecretChat) {
10891     return promise.set_value(Unit());
10892   }
10893 
10894   if (G()->parameters().use_message_db) {
10895     LOG(INFO) << "Delete all messages from " << sender_dialog_id << " in " << dialog_id << " from database";
10896     G()->td_db()->get_messages_db_async()->delete_dialog_messages_by_sender(dialog_id, sender_dialog_id,
10897                                                                             Auto());  // TODO Promise
10898   }
10899 
10900   vector<MessageId> message_ids;
10901   find_messages(d->messages.get(), message_ids, [this, sender_dialog_id](const Message *m) {
10902     return sender_dialog_id == MessagesManager::get_message_sender(m);
10903   });
10904 
10905   vector<int64> deleted_message_ids;
10906   bool need_update_dialog_pos = false;
10907   for (auto message_id : message_ids) {
10908     auto m = get_message(d, message_id);
10909     CHECK(m != nullptr);
10910     CHECK(m->message_id == message_id);
10911     if (can_delete_channel_message(channel_status, m, is_bot)) {
10912       auto p = delete_message(d, message_id, true, &need_update_dialog_pos, "delete_dialog_messages_by_sender");
10913       CHECK(p.get() == m);
10914       deleted_message_ids.push_back(p->message_id.get());
10915     }
10916   }
10917 
10918   if (need_update_dialog_pos) {
10919     send_update_chat_last_message(d, "delete_dialog_messages_by_sender");
10920   }
10921 
10922   send_update_delete_messages(dialog_id, std::move(deleted_message_ids), true, false);
10923 
10924   delete_all_channel_messages_by_sender_on_server(channel_id, sender_dialog_id, 0, std::move(promise));
10925 }
10926 
10927 class MessagesManager::DeleteAllChannelMessagesFromSenderOnServerLogEvent {
10928  public:
10929   ChannelId channel_id_;
10930   DialogId sender_dialog_id_;
10931 
10932   template <class StorerT>
store(StorerT & storer) const10933   void store(StorerT &storer) const {
10934     td::store(channel_id_, storer);
10935     td::store(sender_dialog_id_, storer);
10936   }
10937 
10938   template <class ParserT>
parse(ParserT & parser)10939   void parse(ParserT &parser) {
10940     td::parse(channel_id_, parser);
10941     if (parser.version() >= static_cast<int32>(Version::AddKeyboardButtonFlags)) {
10942       td::parse(sender_dialog_id_, parser);
10943     } else {
10944       UserId user_id;
10945       td::parse(user_id, parser);
10946       sender_dialog_id_ = DialogId(user_id);
10947     }
10948   }
10949 };
10950 
save_delete_all_channel_messages_by_sender_on_server_log_event(ChannelId channel_id,DialogId sender_dialog_id)10951 uint64 MessagesManager::save_delete_all_channel_messages_by_sender_on_server_log_event(ChannelId channel_id,
10952                                                                                        DialogId sender_dialog_id) {
10953   DeleteAllChannelMessagesFromSenderOnServerLogEvent log_event{channel_id, sender_dialog_id};
10954   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::DeleteAllChannelMessagesFromSenderOnServer,
10955                     get_log_event_storer(log_event));
10956 }
10957 
delete_all_channel_messages_by_sender_on_server(ChannelId channel_id,DialogId sender_dialog_id,uint64 log_event_id,Promise<Unit> && promise)10958 void MessagesManager::delete_all_channel_messages_by_sender_on_server(ChannelId channel_id, DialogId sender_dialog_id,
10959                                                                       uint64 log_event_id, Promise<Unit> &&promise) {
10960   if (log_event_id == 0 && G()->parameters().use_chat_info_db) {
10961     log_event_id = save_delete_all_channel_messages_by_sender_on_server_log_event(channel_id, sender_dialog_id);
10962   }
10963 
10964   AffectedHistoryQuery query = [td = td_, sender_dialog_id](DialogId dialog_id,
10965                                                             Promise<AffectedHistory> &&query_promise) {
10966     td->create_handler<DeleteParticipantHistoryQuery>(std::move(query_promise))
10967         ->send(dialog_id.get_channel_id(), sender_dialog_id);
10968   };
10969   run_affected_history_query_until_complete(DialogId(channel_id), std::move(query),
10970                                             sender_dialog_id.get_type() != DialogType::User,
10971                                             get_erase_log_event_promise(log_event_id, std::move(promise)));
10972 }
10973 
delete_dialog_messages_by_date(DialogId dialog_id,int32 min_date,int32 max_date,bool revoke,Promise<Unit> && promise)10974 void MessagesManager::delete_dialog_messages_by_date(DialogId dialog_id, int32 min_date, int32 max_date, bool revoke,
10975                                                      Promise<Unit> &&promise) {
10976   bool is_bot = td_->auth_manager_->is_bot();
10977   CHECK(!is_bot);
10978 
10979   Dialog *d = get_dialog_force(dialog_id, "delete_dialog_messages_by_date");
10980   if (d == nullptr) {
10981     return promise.set_error(Status::Error(400, "Chat not found"));
10982   }
10983 
10984   if (!have_input_peer(dialog_id, AccessRights::Read)) {
10985     return promise.set_error(Status::Error(400, "Can't access the chat"));
10986   }
10987 
10988   if (min_date > max_date) {
10989     return promise.set_error(Status::Error(400, "Wrong date interval specified"));
10990   }
10991 
10992   const int32 telegram_launch_date = 1376438400;
10993   if (max_date < telegram_launch_date) {
10994     return promise.set_value(Unit());
10995   }
10996   if (min_date < telegram_launch_date) {
10997     min_date = telegram_launch_date;
10998   }
10999 
11000   auto current_date = max(G()->unix_time(), 1635000000);
11001   if (min_date >= current_date - 30) {
11002     return promise.set_value(Unit());
11003   }
11004   if (max_date >= current_date - 30) {
11005     max_date = current_date - 31;
11006   }
11007   CHECK(min_date <= max_date);
11008 
11009   switch (dialog_id.get_type()) {
11010     case DialogType::User:
11011       break;
11012     case DialogType::Chat:
11013       if (revoke) {
11014         return promise.set_error(Status::Error(400, "Bulk message revocation is unsupported in basic group chats"));
11015       }
11016       break;
11017     case DialogType::Channel:
11018       return promise.set_error(Status::Error(400, "Bulk message deletion is unsupported in supergroup chats"));
11019     case DialogType::SecretChat:
11020       return promise.set_error(Status::Error(400, "Bulk message deletion is unsupported in secret chats"));
11021     case DialogType::None:
11022     default:
11023       UNREACHABLE();
11024       break;
11025   }
11026 
11027   // TODO delete in database by dates
11028 
11029   vector<MessageId> message_ids;
11030   find_messages_by_date(d->messages.get(), min_date, max_date, message_ids);
11031 
11032   bool need_update_dialog_pos = false;
11033   vector<int64> deleted_message_ids;
11034   for (auto message_id : message_ids) {
11035     auto m = delete_message(d, message_id, true, &need_update_dialog_pos, DELETE_MESSAGE_USER_REQUEST_SOURCE);
11036     CHECK(m != nullptr);
11037     deleted_message_ids.push_back(m->message_id.get());
11038   }
11039 
11040   if (need_update_dialog_pos) {
11041     send_update_chat_last_message(d, "delete_dialog_messages_by_date");
11042   }
11043   send_update_delete_messages(dialog_id, std::move(deleted_message_ids), true, false);
11044 
11045   delete_dialog_messages_by_date_on_server(dialog_id, min_date, max_date, revoke, 0, std::move(promise));
11046 }
11047 
11048 class MessagesManager::DeleteDialogMessagesByDateOnServerLogEvent {
11049  public:
11050   DialogId dialog_id_;
11051   int32 min_date_;
11052   int32 max_date_;
11053   bool revoke_;
11054 
11055   template <class StorerT>
store(StorerT & storer) const11056   void store(StorerT &storer) const {
11057     BEGIN_STORE_FLAGS();
11058     STORE_FLAG(revoke_);
11059     END_STORE_FLAGS();
11060     td::store(dialog_id_, storer);
11061     td::store(min_date_, storer);
11062     td::store(max_date_, storer);
11063   }
11064 
11065   template <class ParserT>
parse(ParserT & parser)11066   void parse(ParserT &parser) {
11067     BEGIN_PARSE_FLAGS();
11068     PARSE_FLAG(revoke_);
11069     END_PARSE_FLAGS();
11070     td::parse(dialog_id_, parser);
11071     td::parse(min_date_, parser);
11072     td::parse(max_date_, parser);
11073   }
11074 };
11075 
save_delete_dialog_messages_by_date_on_server_log_event(DialogId dialog_id,int32 min_date,int32 max_date,bool revoke)11076 uint64 MessagesManager::save_delete_dialog_messages_by_date_on_server_log_event(DialogId dialog_id, int32 min_date,
11077                                                                                 int32 max_date, bool revoke) {
11078   DeleteDialogMessagesByDateOnServerLogEvent log_event{dialog_id, min_date, max_date, revoke};
11079   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::DeleteDialogMessagesByDateOnServer,
11080                     get_log_event_storer(log_event));
11081 }
11082 
delete_dialog_messages_by_date_on_server(DialogId dialog_id,int32 min_date,int32 max_date,bool revoke,uint64 log_event_id,Promise<Unit> && promise)11083 void MessagesManager::delete_dialog_messages_by_date_on_server(DialogId dialog_id, int32 min_date, int32 max_date,
11084                                                                bool revoke, uint64 log_event_id,
11085                                                                Promise<Unit> &&promise) {
11086   if (log_event_id == 0 && G()->parameters().use_chat_info_db) {
11087     log_event_id = save_delete_dialog_messages_by_date_on_server_log_event(dialog_id, min_date, max_date, revoke);
11088   }
11089 
11090   AffectedHistoryQuery query = [td = td_, min_date, max_date, revoke](DialogId dialog_id,
11091                                                                       Promise<AffectedHistory> &&query_promise) {
11092     td->create_handler<DeleteMessagesByDateQuery>(std::move(query_promise))
11093         ->send(dialog_id, min_date, max_date, revoke);
11094   };
11095   run_affected_history_query_until_complete(dialog_id, std::move(query), true,
11096                                             get_erase_log_event_promise(log_event_id, std::move(promise)));
11097 }
11098 
get_unload_dialog_delay() const11099 int32 MessagesManager::get_unload_dialog_delay() const {
11100   constexpr int32 DIALOG_UNLOAD_DELAY = 60;        // seconds
11101   constexpr int32 DIALOG_UNLOAD_BOT_DELAY = 1800;  // seconds
11102 
11103   CHECK(is_message_unload_enabled());
11104   auto default_unload_delay = td_->auth_manager_->is_bot() ? DIALOG_UNLOAD_BOT_DELAY : DIALOG_UNLOAD_DELAY;
11105   return narrow_cast<int32>(G()->shared_config().get_option_integer("message_unload_delay", default_unload_delay));
11106 }
11107 
unload_dialog(DialogId dialog_id)11108 void MessagesManager::unload_dialog(DialogId dialog_id) {
11109   if (G()->close_flag()) {
11110     return;
11111   }
11112 
11113   Dialog *d = get_dialog(dialog_id);
11114   CHECK(d != nullptr);
11115 
11116   if (!d->has_unload_timeout) {
11117     LOG(INFO) << "Don't need to unload " << dialog_id;
11118     // possible right after the dialog was opened
11119     return;
11120   }
11121 
11122   if (!is_message_unload_enabled()) {
11123     // just in case
11124     LOG(INFO) << "Message unload is disabled in " << dialog_id;
11125     d->has_unload_timeout = false;
11126     return;
11127   }
11128 
11129   vector<MessageId> to_unload_message_ids;
11130   int32 left_to_unload = 0;
11131   find_unloadable_messages(d, G()->unix_time_cached() - get_unload_dialog_delay() + 2, d->messages.get(),
11132                            to_unload_message_ids, left_to_unload);
11133 
11134   vector<int64> unloaded_message_ids;
11135   for (auto message_id : to_unload_message_ids) {
11136     unload_message(d, message_id);
11137     unloaded_message_ids.push_back(message_id.get());
11138   }
11139 
11140   if (!unloaded_message_ids.empty()) {
11141     if (!G()->parameters().use_message_db && !d->is_empty) {
11142       d->have_full_history = false;
11143     }
11144 
11145     send_closure_later(
11146         G()->td(), &Td::send_update,
11147         make_tl_object<td_api::updateDeleteMessages>(dialog_id.get(), std::move(unloaded_message_ids), false, true));
11148   }
11149 
11150   if (left_to_unload > 0) {
11151     LOG(DEBUG) << "Need to unload " << left_to_unload << " messages more in " << dialog_id;
11152     pending_unload_dialog_timeout_.add_timeout_in(d->dialog_id.get(), get_unload_dialog_delay());
11153   } else {
11154     d->has_unload_timeout = false;
11155   }
11156 }
11157 
delete_all_dialog_messages(Dialog * d,bool remove_from_dialog_list,bool is_permanently_deleted)11158 void MessagesManager::delete_all_dialog_messages(Dialog *d, bool remove_from_dialog_list, bool is_permanently_deleted) {
11159   CHECK(d != nullptr);
11160   LOG(INFO) << "Delete all messages in " << d->dialog_id
11161             << " with remove_from_dialog_list = " << remove_from_dialog_list
11162             << " and is_permanently_deleted = " << is_permanently_deleted;
11163   if (is_debug_message_op_enabled()) {
11164     d->debug_message_op.emplace_back(Dialog::MessageOp::DeleteAll, MessageId(), MessageContentType::None,
11165                                      remove_from_dialog_list, false, false, "");
11166   }
11167 
11168   if (d->server_unread_count + d->local_unread_count > 0) {
11169     MessageId max_message_id =
11170         d->last_database_message_id.is_valid() ? d->last_database_message_id : d->last_new_message_id;
11171     if (max_message_id.is_valid()) {
11172       read_history_inbox(d->dialog_id, max_message_id, -1, "delete_all_dialog_messages 1");
11173     }
11174     if (d->server_unread_count != 0 || d->local_unread_count != 0) {
11175       set_dialog_last_read_inbox_message_id(d, MessageId::min(), 0, 0, true, "delete_all_dialog_messages 2");
11176     }
11177   }
11178 
11179   if (d->unread_mention_count > 0) {
11180     set_dialog_unread_mention_count(d, 0);
11181     send_update_chat_unread_mention_count(d);
11182   }
11183 
11184   bool has_last_message_id = d->last_message_id != MessageId();
11185   int32 last_message_date = 0;
11186   MessageId last_clear_history_message_id;
11187   if (!remove_from_dialog_list) {
11188     if (has_last_message_id) {
11189       auto m = get_message(d, d->last_message_id);
11190       CHECK(m != nullptr);
11191       last_message_date = m->date;
11192       last_clear_history_message_id = d->last_message_id;
11193     } else {
11194       last_message_date = d->last_clear_history_date;
11195       last_clear_history_message_id = d->last_clear_history_message_id;
11196     }
11197   }
11198 
11199   vector<int64> deleted_message_ids;
11200   do_delete_all_dialog_messages(d, d->messages, is_permanently_deleted, deleted_message_ids);
11201   delete_all_dialog_messages_from_database(d, MessageId::max(), "delete_all_dialog_messages 3");
11202   if (is_permanently_deleted) {
11203     for (auto id : deleted_message_ids) {
11204       d->deleted_message_ids.insert(MessageId{id});
11205     }
11206   }
11207 
11208   if (d->reply_markup_message_id != MessageId()) {
11209     set_dialog_reply_markup(d, MessageId());
11210   }
11211 
11212   set_dialog_first_database_message_id(d, MessageId(), "delete_all_dialog_messages 4");
11213   set_dialog_last_database_message_id(d, MessageId(), "delete_all_dialog_messages 5");
11214   set_dialog_last_clear_history_date(d, last_message_date, last_clear_history_message_id,
11215                                      "delete_all_dialog_messages 6");
11216   d->last_read_all_mentions_message_id = MessageId();                            // it is not needed anymore
11217   d->message_notification_group.max_removed_notification_id = NotificationId();  // it is not needed anymore
11218   d->message_notification_group.max_removed_message_id = MessageId();            // it is not needed anymore
11219   d->mention_notification_group.max_removed_notification_id = NotificationId();  // it is not needed anymore
11220   d->mention_notification_group.max_removed_message_id = MessageId();            // it is not needed anymore
11221   std::fill(d->message_count_by_index.begin(), d->message_count_by_index.end(), 0);
11222   d->notification_id_to_message_id.clear();
11223 
11224   if (has_last_message_id) {
11225     set_dialog_last_message_id(d, MessageId(), "delete_all_dialog_messages 7");
11226     send_update_chat_last_message(d, "delete_all_dialog_messages 8");
11227   }
11228   if (remove_from_dialog_list) {
11229     set_dialog_order(d, DEFAULT_ORDER, true, false, "delete_all_dialog_messages 9");
11230   } else {
11231     update_dialog_pos(d, "delete_all_dialog_messages 10");
11232   }
11233 
11234   on_dialog_updated(d->dialog_id, "delete_all_dialog_messages 11");
11235 
11236   send_update_delete_messages(d->dialog_id, std::move(deleted_message_ids), is_permanently_deleted, false);
11237 }
11238 
on_dialog_deleted(DialogId dialog_id,Promise<Unit> && promise)11239 void MessagesManager::on_dialog_deleted(DialogId dialog_id, Promise<Unit> &&promise) {
11240   LOG(INFO) << "Delete " << dialog_id;
11241   Dialog *d = get_dialog_force(dialog_id, "on_dialog_deleted");
11242   if (d == nullptr) {
11243     return promise.set_value(Unit());
11244   }
11245 
11246   delete_all_dialog_messages(d, true, false);
11247   if (dialog_id.get_type() != DialogType::SecretChat) {
11248     d->have_full_history = false;
11249     d->is_empty = false;
11250     d->need_restore_reply_markup = true;
11251   }
11252   recently_found_dialogs_.remove_dialog(dialog_id);
11253   recently_opened_dialogs_.remove_dialog(dialog_id);
11254   if (dialog_id.get_type() == DialogType::Channel) {
11255     G()->td_db()->get_binlog_pmc()->erase(get_channel_pts_key(dialog_id));
11256   }
11257 
11258   close_dialog(d);
11259   promise.set_value(Unit());
11260 }
11261 
on_update_dialog_group_call_rights(DialogId dialog_id)11262 void MessagesManager::on_update_dialog_group_call_rights(DialogId dialog_id) {
11263   auto d = get_dialog(dialog_id);
11264   if (d == nullptr) {
11265     // nothing to do
11266     return;
11267   }
11268 
11269   if (d->active_group_call_id.is_valid()) {
11270     td_->group_call_manager_->on_update_group_call_rights(d->active_group_call_id);
11271   }
11272 }
11273 
read_all_dialog_mentions(DialogId dialog_id,Promise<Unit> && promise)11274 void MessagesManager::read_all_dialog_mentions(DialogId dialog_id, Promise<Unit> &&promise) {
11275   Dialog *d = get_dialog_force(dialog_id, "read_all_dialog_mentions");
11276   if (d == nullptr) {
11277     return promise.set_error(Status::Error(400, "Chat not found"));
11278   }
11279 
11280   LOG(INFO) << "Receive readAllChatMentions request in " << dialog_id << " with " << d->unread_mention_count
11281             << " unread mentions";
11282   if (!have_input_peer(dialog_id, AccessRights::Read)) {
11283     return promise.set_error(Status::Error(400, "Chat is not accessible"));
11284   }
11285   if (dialog_id.get_type() == DialogType::SecretChat) {
11286     CHECK(d->unread_mention_count == 0);
11287     return promise.set_value(Unit());
11288   }
11289 
11290   if (d->last_new_message_id > d->last_read_all_mentions_message_id) {
11291     d->last_read_all_mentions_message_id = d->last_new_message_id;
11292     on_dialog_updated(dialog_id, "read_all_dialog_mentions");
11293   }
11294 
11295   vector<MessageId> message_ids;
11296   find_messages(d->messages.get(), message_ids, [](const Message *m) { return m->contains_unread_mention; });
11297 
11298   LOG(INFO) << "Found " << message_ids.size() << " messages with unread mentions in memory";
11299   bool is_update_sent = false;
11300   for (auto message_id : message_ids) {
11301     auto m = get_message(d, message_id);
11302     CHECK(m != nullptr);
11303     CHECK(m->contains_unread_mention);
11304     CHECK(m->message_id == message_id);
11305     CHECK(m->message_id.is_valid());
11306     remove_message_notification_id(d, m, true, false);  // should be called before contains_unread_mention is updated
11307     m->contains_unread_mention = false;
11308 
11309     send_closure(G()->td(), &Td::send_update,
11310                  make_tl_object<td_api::updateMessageMentionRead>(dialog_id.get(), m->message_id.get(), 0));
11311     is_update_sent = true;
11312     on_message_changed(d, m, true, "read_all_dialog_mentions");
11313   }
11314 
11315   if (d->unread_mention_count != 0) {
11316     set_dialog_unread_mention_count(d, 0);
11317     if (!is_update_sent) {
11318       send_update_chat_unread_mention_count(d);
11319     } else {
11320       LOG(INFO) << "Update unread mention message count in " << dialog_id << " to " << d->unread_mention_count;
11321       on_dialog_updated(dialog_id, "read_all_dialog_mentions");
11322     }
11323   }
11324   remove_message_dialog_notifications(d, MessageId::max(), true, "read_all_dialog_mentions");
11325 
11326   read_all_dialog_mentions_on_server(dialog_id, 0, std::move(promise));
11327 }
11328 
11329 class MessagesManager::ReadAllDialogMentionsOnServerLogEvent {
11330  public:
11331   DialogId dialog_id_;
11332 
11333   template <class StorerT>
store(StorerT & storer) const11334   void store(StorerT &storer) const {
11335     td::store(dialog_id_, storer);
11336   }
11337 
11338   template <class ParserT>
parse(ParserT & parser)11339   void parse(ParserT &parser) {
11340     td::parse(dialog_id_, parser);
11341   }
11342 };
11343 
save_read_all_dialog_mentions_on_server_log_event(DialogId dialog_id)11344 uint64 MessagesManager::save_read_all_dialog_mentions_on_server_log_event(DialogId dialog_id) {
11345   ReadAllDialogMentionsOnServerLogEvent log_event{dialog_id};
11346   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::ReadAllDialogMentionsOnServer,
11347                     get_log_event_storer(log_event));
11348 }
11349 
read_all_dialog_mentions_on_server(DialogId dialog_id,uint64 log_event_id,Promise<Unit> && promise)11350 void MessagesManager::read_all_dialog_mentions_on_server(DialogId dialog_id, uint64 log_event_id,
11351                                                          Promise<Unit> &&promise) {
11352   if (log_event_id == 0 && G()->parameters().use_message_db) {
11353     log_event_id = save_read_all_dialog_mentions_on_server_log_event(dialog_id);
11354   }
11355 
11356   AffectedHistoryQuery query = [td = td_](DialogId dialog_id, Promise<AffectedHistory> &&query_promise) {
11357     td->create_handler<ReadMentionsQuery>(std::move(query_promise))->send(dialog_id);
11358   };
11359   run_affected_history_query_until_complete(dialog_id, std::move(query), false,
11360                                             get_erase_log_event_promise(log_event_id, std::move(promise)));
11361 }
11362 
read_message_content_from_updates(MessageId message_id)11363 void MessagesManager::read_message_content_from_updates(MessageId message_id) {
11364   if (!message_id.is_valid() || !message_id.is_server()) {
11365     LOG(ERROR) << "Incoming update tries to read content of " << message_id;
11366     return;
11367   }
11368 
11369   Dialog *d = get_dialog_by_message_id(message_id);
11370   if (d != nullptr) {
11371     Message *m = get_message(d, message_id);
11372     CHECK(m != nullptr);
11373     read_message_content(d, m, false, "read_message_content_from_updates");
11374   }
11375 }
11376 
read_channel_message_content_from_updates(Dialog * d,MessageId message_id)11377 void MessagesManager::read_channel_message_content_from_updates(Dialog *d, MessageId message_id) {
11378   CHECK(d != nullptr);
11379   if (!message_id.is_valid() || !message_id.is_server()) {
11380     LOG(ERROR) << "Incoming update tries to read content of " << message_id << " in " << d->dialog_id;
11381     return;
11382   }
11383 
11384   Message *m = get_message_force(d, message_id, "read_channel_message_content_from_updates");
11385   if (m != nullptr) {
11386     read_message_content(d, m, false, "read_channel_message_content_from_updates");
11387   } else if (message_id > d->last_new_message_id) {
11388     get_channel_difference(d->dialog_id, d->pts, true, "read_channel_message_content_from_updates");
11389   }
11390 }
11391 
read_message_content(Dialog * d,Message * m,bool is_local_read,const char * source)11392 bool MessagesManager::read_message_content(Dialog *d, Message *m, bool is_local_read, const char *source) {
11393   LOG_CHECK(m != nullptr) << source;
11394   CHECK(!m->message_id.is_scheduled());
11395   bool is_mention_read = update_message_contains_unread_mention(d, m, false, "read_message_content");
11396   bool is_content_read =
11397       update_opened_message_content(m->content.get()) | ttl_on_open(d, m, Time::now(), is_local_read);
11398 
11399   LOG(INFO) << "Read message content of " << m->message_id << " in " << d->dialog_id
11400             << ": is_mention_read = " << is_mention_read << ", is_content_read = " << is_content_read;
11401   if (is_mention_read || is_content_read) {
11402     on_message_changed(d, m, true, "read_message_content");
11403     if (is_content_read) {
11404       send_closure(G()->td(), &Td::send_update,
11405                    make_tl_object<td_api::updateMessageContentOpened>(d->dialog_id.get(), m->message_id.get()));
11406     }
11407     return true;
11408   }
11409   return false;
11410 }
11411 
has_incoming_notification(DialogId dialog_id,const Message * m) const11412 bool MessagesManager::has_incoming_notification(DialogId dialog_id, const Message *m) const {
11413   if (m->is_from_scheduled) {
11414     return true;
11415   }
11416   return !m->is_outgoing && dialog_id != get_my_dialog_id();
11417 }
11418 
calc_new_unread_count_from_last_unread(Dialog * d,MessageId max_message_id,MessageType type) const11419 int32 MessagesManager::calc_new_unread_count_from_last_unread(Dialog *d, MessageId max_message_id,
11420                                                               MessageType type) const {
11421   CHECK(!max_message_id.is_scheduled());
11422   MessagesConstIterator it(d, max_message_id);
11423   if (*it == nullptr || (*it)->message_id != max_message_id) {
11424     return -1;
11425   }
11426 
11427   int32 unread_count = type == MessageType::Server ? d->server_unread_count : d->local_unread_count;
11428   while (*it != nullptr && (*it)->message_id > d->last_read_inbox_message_id) {
11429     if (has_incoming_notification(d->dialog_id, *it) && (*it)->message_id.get_type() == type) {
11430       unread_count--;
11431     }
11432     --it;
11433   }
11434   if (*it == nullptr || (*it)->message_id != d->last_read_inbox_message_id) {
11435     return -1;
11436   }
11437 
11438   LOG(INFO) << "Found " << unread_count << " unread messages in " << d->dialog_id << " from last unread message";
11439   return unread_count;
11440 }
11441 
calc_new_unread_count_from_the_end(Dialog * d,MessageId max_message_id,MessageType type,int32 hint_unread_count) const11442 int32 MessagesManager::calc_new_unread_count_from_the_end(Dialog *d, MessageId max_message_id, MessageType type,
11443                                                           int32 hint_unread_count) const {
11444   CHECK(!max_message_id.is_scheduled());
11445   int32 unread_count = 0;
11446   MessagesConstIterator it(d, MessageId::max());
11447   while (*it != nullptr && (*it)->message_id > max_message_id) {
11448     if (has_incoming_notification(d->dialog_id, *it) && (*it)->message_id.get_type() == type) {
11449       unread_count++;
11450     }
11451     --it;
11452   }
11453 
11454   bool is_count_exact = d->last_message_id.is_valid() && *it != nullptr;
11455   if (hint_unread_count >= 0) {
11456     if (is_count_exact) {
11457       if (hint_unread_count == unread_count) {
11458         return hint_unread_count;
11459       }
11460     } else {
11461       if (hint_unread_count >= unread_count) {
11462         return hint_unread_count;
11463       }
11464     }
11465 
11466     // hint_unread_count is definitely wrong, ignore it
11467 
11468     if (need_unread_counter(d->order)) {
11469       LOG(ERROR) << "Receive hint_unread_count = " << hint_unread_count << ", but found " << unread_count
11470                  << " unread messages in " << d->dialog_id;
11471     }
11472   }
11473 
11474   if (!is_count_exact) {
11475     // unread count is likely to be calculated wrong, so ignore it
11476     return -1;
11477   }
11478 
11479   LOG(INFO) << "Found " << unread_count << " unread messages in " << d->dialog_id << " from the end";
11480   return unread_count;
11481 }
11482 
calc_new_unread_count(Dialog * d,MessageId max_message_id,MessageType type,int32 hint_unread_count) const11483 int32 MessagesManager::calc_new_unread_count(Dialog *d, MessageId max_message_id, MessageType type,
11484                                              int32 hint_unread_count) const {
11485   CHECK(!max_message_id.is_scheduled());
11486   if (d->is_empty) {
11487     return 0;
11488   }
11489 
11490   if (!d->last_read_inbox_message_id.is_valid()) {
11491     return calc_new_unread_count_from_the_end(d, max_message_id, type, hint_unread_count);
11492   }
11493 
11494   if (!d->last_message_id.is_valid() ||
11495       (d->last_message_id.get() - max_message_id.get() > max_message_id.get() - d->last_read_inbox_message_id.get())) {
11496     int32 unread_count = calc_new_unread_count_from_last_unread(d, max_message_id, type);
11497     return unread_count >= 0 ? unread_count
11498                              : calc_new_unread_count_from_the_end(d, max_message_id, type, hint_unread_count);
11499   } else {
11500     int32 unread_count = calc_new_unread_count_from_the_end(d, max_message_id, type, hint_unread_count);
11501     return unread_count >= 0 ? unread_count : calc_new_unread_count_from_last_unread(d, max_message_id, type);
11502   }
11503 }
11504 
repair_server_unread_count(DialogId dialog_id,int32 unread_count)11505 void MessagesManager::repair_server_unread_count(DialogId dialog_id, int32 unread_count) {
11506   if (td_->auth_manager_->is_bot() || !have_input_peer(dialog_id, AccessRights::Read)) {
11507     return;
11508   }
11509   if (pending_read_history_timeout_.has_timeout(dialog_id.get())) {
11510     return;  // postpone until read history request is sent
11511   }
11512 
11513   LOG(INFO) << "Repair server unread count in " << dialog_id << " from " << unread_count;
11514   create_actor<SleepActor>("RepairServerUnreadCountSleepActor", 0.2,
11515                            PromiseCreator::lambda([actor_id = actor_id(this), dialog_id](Result<Unit> result) {
11516                              send_closure(actor_id, &MessagesManager::send_get_dialog_query, dialog_id, Promise<Unit>(),
11517                                           0, "repair_server_unread_count");
11518                            }))
11519       .release();
11520 }
11521 
repair_channel_server_unread_count(Dialog * d)11522 void MessagesManager::repair_channel_server_unread_count(Dialog *d) {
11523   CHECK(d != nullptr);
11524   CHECK(d->dialog_id.get_type() == DialogType::Channel);
11525 
11526   if (td_->auth_manager_->is_bot()) {
11527     return;
11528   }
11529   if (d->last_read_inbox_message_id >= d->last_new_message_id) {
11530     // all messages are already read
11531     return;
11532   }
11533   if (!need_unread_counter(d->order)) {
11534     // there are no unread counters in left channels
11535     return;
11536   }
11537   if (!d->need_repair_channel_server_unread_count) {
11538     d->need_repair_channel_server_unread_count = true;
11539     on_dialog_updated(d->dialog_id, "repair_channel_server_unread_count");
11540   }
11541 
11542   LOG(INFO) << "Reload ChannelFull for " << d->dialog_id << " to repair unread message counts";
11543   get_dialog_info_full(d->dialog_id, Auto(), "repair_channel_server_unread_count");
11544 }
11545 
read_history_inbox(DialogId dialog_id,MessageId max_message_id,int32 unread_count,const char * source)11546 void MessagesManager::read_history_inbox(DialogId dialog_id, MessageId max_message_id, int32 unread_count,
11547                                          const char *source) {
11548   CHECK(!max_message_id.is_scheduled());
11549 
11550   if (td_->auth_manager_->is_bot()) {
11551     return;
11552   }
11553 
11554   Dialog *d = get_dialog_force(dialog_id, "read_history_inbox");
11555   if (d != nullptr) {
11556     if (d->need_repair_channel_server_unread_count) {
11557       d->need_repair_channel_server_unread_count = false;
11558       on_dialog_updated(dialog_id, "read_history_inbox");
11559     }
11560 
11561     // there can be updateReadHistoryInbox up to message 0, if messages where read and then all messages where deleted
11562     if (!max_message_id.is_valid() && max_message_id != MessageId()) {
11563       LOG(ERROR) << "Receive read inbox update in " << dialog_id << " up to " << max_message_id << " from " << source;
11564       return;
11565     }
11566     if (d->is_last_read_inbox_message_id_inited && max_message_id <= d->last_read_inbox_message_id) {
11567       LOG(INFO) << "Receive read inbox update in " << dialog_id << " up to " << max_message_id << " from " << source
11568                 << ", but all messages have already been read up to " << d->last_read_inbox_message_id;
11569       if (max_message_id == d->last_read_inbox_message_id && unread_count >= 0 &&
11570           unread_count != d->server_unread_count) {
11571         set_dialog_last_read_inbox_message_id(d, MessageId::min(), unread_count, d->local_unread_count, true, source);
11572       }
11573       return;
11574     }
11575 
11576     if (max_message_id != MessageId() && max_message_id.is_yet_unsent()) {
11577       LOG(ERROR) << "Tried to update last read inbox message in " << dialog_id << " with " << max_message_id << " from "
11578                  << source;
11579       return;
11580     }
11581 
11582     if (max_message_id != MessageId() && unread_count > 0 && max_message_id >= d->last_new_message_id &&
11583         max_message_id >= d->last_message_id && max_message_id >= d->last_database_message_id) {
11584       if (d->last_new_message_id.is_valid()) {
11585         LOG(ERROR) << "Have unknown " << unread_count << " unread messages up to " << max_message_id << " in "
11586                    << dialog_id << " with last_new_message_id = " << d->last_new_message_id
11587                    << ", last_message_id = " << d->last_message_id
11588                    << ", last_database_message_id = " << d->last_database_message_id << " from " << source;
11589       }
11590       unread_count = 0;
11591     }
11592 
11593     LOG_IF(INFO, d->last_new_message_id.is_valid() && max_message_id > d->last_new_message_id &&
11594                      max_message_id > d->max_notification_message_id && max_message_id.is_server() &&
11595                      dialog_id.get_type() != DialogType::Channel && !running_get_difference_)
11596         << "Receive read inbox update up to unknown " << max_message_id << " in " << dialog_id << " from " << source
11597         << ". Last new is " << d->last_new_message_id << ", unread_count = " << unread_count
11598         << ". Possible only for deleted incoming message";
11599 
11600     if (dialog_id.get_type() == DialogType::SecretChat) {
11601       ttl_read_history(d, false, max_message_id, d->last_read_inbox_message_id, Time::now());
11602     }
11603 
11604     if (max_message_id > d->last_new_message_id && dialog_id.get_type() == DialogType::Channel) {
11605       LOG(INFO) << "Schedule getDifference in " << dialog_id.get_channel_id();
11606       channel_get_difference_retry_timeout_.add_timeout_in(dialog_id.get(), 0.001);
11607     }
11608 
11609     int32 server_unread_count = calc_new_unread_count(d, max_message_id, MessageType::Server, unread_count);
11610     int32 local_unread_count =
11611         d->local_unread_count == 0 ? 0 : calc_new_unread_count(d, max_message_id, MessageType::Local, -1);
11612 
11613     if (server_unread_count < 0) {
11614       server_unread_count = unread_count >= 0 ? unread_count : d->server_unread_count;
11615       if (dialog_id.get_type() != DialogType::SecretChat && have_input_peer(dialog_id, AccessRights::Read) &&
11616           need_unread_counter(d->order)) {
11617         d->need_repair_server_unread_count = true;
11618         repair_server_unread_count(dialog_id, server_unread_count);
11619       }
11620     }
11621     if (local_unread_count < 0) {
11622       // TODO repair local unread count
11623       local_unread_count = d->local_unread_count;
11624     }
11625 
11626     set_dialog_last_read_inbox_message_id(d, max_message_id, server_unread_count, local_unread_count, true, source);
11627 
11628     if (d->is_marked_as_unread && max_message_id != MessageId()) {
11629       set_dialog_is_marked_as_unread(d, false);
11630     }
11631   } else {
11632     LOG(INFO) << "Receive read inbox about unknown " << dialog_id << " from " << source;
11633   }
11634 }
11635 
read_history_outbox(DialogId dialog_id,MessageId max_message_id,int32 read_date)11636 void MessagesManager::read_history_outbox(DialogId dialog_id, MessageId max_message_id, int32 read_date) {
11637   CHECK(!max_message_id.is_scheduled());
11638 
11639   if (td_->auth_manager_->is_bot()) {
11640     return;
11641   }
11642 
11643   Dialog *d = get_dialog_force(dialog_id, "read_history_outbox");
11644   if (d != nullptr) {
11645     if (!max_message_id.is_valid()) {
11646       LOG(ERROR) << "Receive read outbox update in " << dialog_id << " with " << max_message_id;
11647       return;
11648     }
11649     if (max_message_id <= d->last_read_outbox_message_id) {
11650       LOG(INFO) << "Receive read outbox update up to " << max_message_id
11651                 << ", but all messages have already been read up to " << d->last_read_outbox_message_id;
11652       return;
11653     }
11654 
11655     if (max_message_id.is_yet_unsent()) {
11656       LOG(ERROR) << "Tried to update last read outbox message with " << max_message_id;
11657       return;
11658     }
11659 
11660     // it is impossible for just sent outgoing messages because updates are ordered by pts
11661     LOG_IF(INFO, d->last_new_message_id.is_valid() && max_message_id > d->last_new_message_id &&
11662                      dialog_id.get_type() != DialogType::Channel)
11663         << "Receive read outbox update about unknown " << max_message_id << " in " << dialog_id << " with last new "
11664         << d->last_new_message_id << ". Possible only for deleted outgoing message";
11665 
11666     if (dialog_id.get_type() == DialogType::SecretChat) {
11667       double server_time = Time::now();
11668       double read_time = server_time;
11669       if (read_date <= 0) {
11670         LOG(ERROR) << "Receive wrong read date " << read_date << " in " << dialog_id;
11671       } else if (read_date < server_time) {
11672         read_time = read_date;
11673       }
11674       ttl_read_history(d, true, max_message_id, d->last_read_outbox_message_id, read_time);
11675     }
11676 
11677     set_dialog_last_read_outbox_message_id(d, max_message_id);
11678   } else {
11679     LOG(INFO) << "Receive read outbox update about unknown " << dialog_id;
11680   }
11681 }
11682 
need_unread_counter(int64 dialog_order)11683 bool MessagesManager::need_unread_counter(int64 dialog_order) {
11684   return dialog_order != DEFAULT_ORDER;
11685 }
11686 
get_dialog_total_count(const DialogList & list) const11687 int32 MessagesManager::get_dialog_total_count(const DialogList &list) const {
11688   int32 sponsored_dialog_count = 0;
11689   if (sponsored_dialog_id_.is_valid() && list.dialog_list_id == DialogListId(FolderId::main())) {
11690     auto d = get_dialog(sponsored_dialog_id_);
11691     CHECK(d != nullptr);
11692     if (is_dialog_sponsored(d)) {
11693       sponsored_dialog_count = 1;
11694     }
11695   }
11696   if (list.server_dialog_total_count_ != -1 && list.secret_chat_total_count_ != -1) {
11697     return std::max(list.server_dialog_total_count_ + list.secret_chat_total_count_,
11698                     list.in_memory_dialog_total_count_) +
11699            sponsored_dialog_count;
11700   }
11701   if (list.list_last_dialog_date_ == MAX_DIALOG_DATE) {
11702     return list.in_memory_dialog_total_count_ + sponsored_dialog_count;
11703   }
11704   return list.in_memory_dialog_total_count_ + sponsored_dialog_count + 1;
11705 }
11706 
repair_server_dialog_total_count(DialogListId dialog_list_id)11707 void MessagesManager::repair_server_dialog_total_count(DialogListId dialog_list_id) {
11708   if (td_->auth_manager_->is_bot()) {
11709     return;
11710   }
11711   if (!dialog_list_id.is_folder()) {
11712     // can repair total count only in folders
11713     return;
11714   }
11715 
11716   LOG(INFO) << "Repair total chat count in " << dialog_list_id;
11717   send_closure(td_->create_net_actor<GetDialogListActor>(Promise<Unit>()), &GetDialogListActor::send,
11718                dialog_list_id.get_folder_id(), 2147483647, ServerMessageId(), DialogId(), 1,
11719                get_sequence_dispatcher_id(DialogId(), MessageContentType::None));
11720 }
11721 
repair_secret_chat_total_count(DialogListId dialog_list_id)11722 void MessagesManager::repair_secret_chat_total_count(DialogListId dialog_list_id) {
11723   if (td_->auth_manager_->is_bot()) {
11724     return;
11725   }
11726 
11727   if (G()->parameters().use_message_db && dialog_list_id.is_folder()) {
11728     // race-prone
11729     G()->td_db()->get_dialog_db_async()->get_secret_chat_count(
11730         dialog_list_id.get_folder_id(),
11731         PromiseCreator::lambda([actor_id = actor_id(this), dialog_list_id](Result<int32> result) {
11732           if (result.is_error()) {
11733             return;
11734           }
11735           send_closure(actor_id, &MessagesManager::on_get_secret_chat_total_count, dialog_list_id, result.move_as_ok());
11736         }));
11737   } else {
11738     int32 total_count = 0;
11739     auto *list = get_dialog_list(dialog_list_id);
11740     CHECK(list != nullptr);
11741     for (auto &folder_id : get_dialog_list_folder_ids(*list)) {
11742       const auto *folder_list = get_dialog_list(DialogListId(folder_id));
11743       CHECK(folder_list != nullptr);
11744       if (folder_list->need_unread_count_recalc_) {
11745         // can't repair total secret chat count yet
11746         return;
11747       }
11748 
11749       const auto *folder = get_dialog_folder(folder_id);
11750       CHECK(folder != nullptr);
11751       for (const auto &dialog_date : folder->ordered_dialogs_) {
11752         auto dialog_id = dialog_date.get_dialog_id();
11753         if (dialog_id.get_type() == DialogType::SecretChat && dialog_date.get_order() != DEFAULT_ORDER) {
11754           total_count++;
11755         }
11756       }
11757     }
11758     on_get_secret_chat_total_count(dialog_list_id, total_count);
11759   }
11760 }
11761 
on_get_secret_chat_total_count(DialogListId dialog_list_id,int32 total_count)11762 void MessagesManager::on_get_secret_chat_total_count(DialogListId dialog_list_id, int32 total_count) {
11763   if (G()->close_flag()) {
11764     return;
11765   }
11766 
11767   CHECK(!td_->auth_manager_->is_bot());
11768   auto *list = get_dialog_list(dialog_list_id);
11769   if (list == nullptr) {
11770     // just in case
11771     return;
11772   }
11773   CHECK(total_count >= 0);
11774   if (list->secret_chat_total_count_ != total_count) {
11775     auto old_dialog_total_count = get_dialog_total_count(*list);
11776     list->secret_chat_total_count_ = total_count;
11777     if (list->is_dialog_unread_count_inited_) {
11778       if (old_dialog_total_count != get_dialog_total_count(*list)) {
11779         send_update_unread_chat_count(*list, DialogId(), true, "on_get_secret_chat_total_count");
11780       } else {
11781         save_unread_chat_count(*list);
11782       }
11783     }
11784   }
11785 }
11786 
recalc_unread_count(DialogListId dialog_list_id,int32 old_dialog_total_count,bool force)11787 void MessagesManager::recalc_unread_count(DialogListId dialog_list_id, int32 old_dialog_total_count, bool force) {
11788   if (G()->close_flag() || td_->auth_manager_->is_bot() || !G()->parameters().use_message_db) {
11789     return;
11790   }
11791 
11792   auto *list_ptr = get_dialog_list(dialog_list_id);
11793   CHECK(list_ptr != nullptr);
11794   auto &list = *list_ptr;
11795   if (!list.need_unread_count_recalc_ && !force) {
11796     return;
11797   }
11798   LOG(INFO) << "Recalculate unread counts in " << dialog_list_id;
11799   list.need_unread_count_recalc_ = false;
11800   list.is_message_unread_count_inited_ = true;
11801   list.is_dialog_unread_count_inited_ = true;
11802 
11803   int32 message_total_count = 0;
11804   int32 message_muted_count = 0;
11805   int32 dialog_total_count = 0;
11806   int32 dialog_muted_count = 0;
11807   int32 dialog_marked_count = 0;
11808   int32 dialog_muted_marked_count = 0;
11809   int32 server_dialog_total_count = 0;
11810   int32 secret_chat_total_count = 0;
11811   for (auto folder_id : get_dialog_list_folder_ids(list)) {
11812     const auto &folder = *get_dialog_folder(folder_id);
11813     for (const auto &dialog_date : folder.ordered_dialogs_) {
11814       if (dialog_date.get_order() == DEFAULT_ORDER) {
11815         break;
11816       }
11817 
11818       auto dialog_id = dialog_date.get_dialog_id();
11819       Dialog *d = get_dialog(dialog_id);
11820       CHECK(d != nullptr);
11821       if (!is_dialog_in_list(d, dialog_list_id)) {
11822         continue;
11823       }
11824 
11825       int unread_count = d->server_unread_count + d->local_unread_count;
11826       if (need_unread_counter(d->order) && (unread_count > 0 || d->is_marked_as_unread)) {
11827         message_total_count += unread_count;
11828         dialog_total_count++;
11829         if (unread_count == 0 && d->is_marked_as_unread) {
11830           dialog_marked_count++;
11831         }
11832 
11833         LOG(DEBUG) << "Have " << unread_count << " messages in " << dialog_id;
11834         if (is_dialog_muted(d)) {
11835           message_muted_count += unread_count;
11836           dialog_muted_count++;
11837           if (unread_count == 0 && d->is_marked_as_unread) {
11838             dialog_muted_marked_count++;
11839           }
11840         }
11841       }
11842       if (d->order != DEFAULT_ORDER) {  // must not count sponsored dialog, which is added independently
11843         if (dialog_id.get_type() == DialogType::SecretChat) {
11844           secret_chat_total_count++;
11845         } else {
11846           server_dialog_total_count++;
11847         }
11848       }
11849     }
11850   }
11851 
11852   if (list.unread_message_total_count_ != message_total_count ||
11853       list.unread_message_muted_count_ != message_muted_count) {
11854     list.unread_message_total_count_ = message_total_count;
11855     list.unread_message_muted_count_ = message_muted_count;
11856     send_update_unread_message_count(list, DialogId(), true, "recalc_unread_count");
11857   }
11858 
11859   if (old_dialog_total_count == -1) {
11860     old_dialog_total_count = get_dialog_total_count(list);
11861   }
11862   bool need_save = false;
11863   if (list.list_last_dialog_date_ == MAX_DIALOG_DATE) {
11864     if (server_dialog_total_count != list.server_dialog_total_count_ ||
11865         secret_chat_total_count != list.secret_chat_total_count_) {
11866       list.server_dialog_total_count_ = server_dialog_total_count;
11867       list.secret_chat_total_count_ = secret_chat_total_count;
11868       need_save = true;
11869     }
11870   } else {
11871     if (list.server_dialog_total_count_ == -1) {
11872       // recalc_unread_count is called only after getDialogs request; it is unneeded to call getDialogs again
11873       repair_server_dialog_total_count(dialog_list_id);
11874     }
11875 
11876     if (list.secret_chat_total_count_ == -1) {
11877       repair_secret_chat_total_count(dialog_list_id);
11878     }
11879   }
11880   if (list.unread_dialog_total_count_ != dialog_total_count || list.unread_dialog_muted_count_ != dialog_muted_count ||
11881       list.unread_dialog_marked_count_ != dialog_marked_count ||
11882       list.unread_dialog_muted_marked_count_ != dialog_muted_marked_count ||
11883       old_dialog_total_count != get_dialog_total_count(list)) {
11884     list.unread_dialog_total_count_ = dialog_total_count;
11885     list.unread_dialog_muted_count_ = dialog_muted_count;
11886     list.unread_dialog_marked_count_ = dialog_marked_count;
11887     list.unread_dialog_muted_marked_count_ = dialog_muted_marked_count;
11888     send_update_unread_chat_count(list, DialogId(), true, "recalc_unread_count");
11889   } else if (need_save) {
11890     save_unread_chat_count(list);
11891   }
11892 }
11893 
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)11894 void MessagesManager::set_dialog_last_read_inbox_message_id(Dialog *d, MessageId message_id, int32 server_unread_count,
11895                                                             int32 local_unread_count, bool force_update,
11896                                                             const char *source) {
11897   CHECK(!message_id.is_scheduled());
11898 
11899   if (td_->auth_manager_->is_bot()) {
11900     return;
11901   }
11902 
11903   CHECK(d != nullptr);
11904   LOG(INFO) << "Update last read inbox message in " << d->dialog_id << " from " << d->last_read_inbox_message_id
11905             << " to " << message_id << " and update unread message count from " << d->server_unread_count << " + "
11906             << d->local_unread_count << " to " << server_unread_count << " + " << local_unread_count << " from "
11907             << source;
11908   if (message_id != MessageId::min()) {
11909     d->last_read_inbox_message_id = message_id;
11910     d->is_last_read_inbox_message_id_inited = true;
11911   }
11912   int32 old_unread_count = d->server_unread_count + d->local_unread_count;
11913   d->server_unread_count = server_unread_count;
11914   d->local_unread_count = local_unread_count;
11915 
11916   if (need_unread_counter(d->order)) {
11917     const int32 new_unread_count = d->server_unread_count + d->local_unread_count;
11918     for (auto &list : get_dialog_lists(d)) {
11919       int32 delta = new_unread_count - old_unread_count;
11920       if (delta != 0 && list.is_message_unread_count_inited_) {
11921         list.unread_message_total_count_ += delta;
11922         if (is_dialog_muted(d)) {
11923           list.unread_message_muted_count_ += delta;
11924         }
11925         send_update_unread_message_count(list, d->dialog_id, force_update, source);
11926       }
11927       delta = static_cast<int32>(new_unread_count != 0) - static_cast<int32>(old_unread_count != 0);
11928       if (delta != 0 && list.is_dialog_unread_count_inited_) {
11929         if (d->is_marked_as_unread) {
11930           list.unread_dialog_marked_count_ -= delta;
11931         } else {
11932           list.unread_dialog_total_count_ += delta;
11933         }
11934         if (is_dialog_muted(d)) {
11935           if (d->is_marked_as_unread) {
11936             list.unread_dialog_muted_marked_count_ -= delta;
11937           } else {
11938             list.unread_dialog_muted_count_ += delta;
11939           }
11940         }
11941         send_update_unread_chat_count(list, d->dialog_id, force_update, source);
11942       }
11943     }
11944 
11945     bool was_unread = old_unread_count != 0 || d->is_marked_as_unread;
11946     bool is_unread = new_unread_count != 0 || d->is_marked_as_unread;
11947     if (!dialog_filters_.empty() && was_unread != is_unread) {
11948       update_dialog_lists(d, get_dialog_positions(d), true, false, "set_dialog_last_read_inbox_message_id");
11949     }
11950   }
11951 
11952   if (message_id != MessageId::min() && d->last_read_inbox_message_id.is_valid() &&
11953       (d->order != DEFAULT_ORDER || is_dialog_sponsored(d))) {
11954     VLOG(notifications) << "Remove some notifications in " << d->dialog_id
11955                         << " after updating last read inbox message to " << message_id
11956                         << " and unread message count to " << server_unread_count << " + " << local_unread_count
11957                         << " from " << source;
11958     if (d->message_notification_group.group_id.is_valid()) {
11959       auto total_count = get_dialog_pending_notification_count(d, false);
11960       if (total_count == 0) {
11961         set_dialog_last_notification(d->dialog_id, d->message_notification_group, 0, NotificationId(), source);
11962       }
11963       if (!d->pending_new_message_notifications.empty()) {
11964         for (auto &it : d->pending_new_message_notifications) {
11965           if (it.second <= message_id) {
11966             it.first = DialogId();
11967           }
11968         }
11969         flush_pending_new_message_notifications(d->dialog_id, false, DialogId(UserId(static_cast<int64>(1))));
11970       }
11971       total_count -= static_cast<int32>(d->pending_new_message_notifications.size());
11972       if (total_count < 0) {
11973         LOG(ERROR) << "Total message notification count is " << total_count << " in " << d->dialog_id
11974                    << " with old unread_count = " << old_unread_count << " and " << d->pending_new_message_notifications
11975                    << " pending new message notifications after reading history up to " << message_id;
11976         total_count = 0;
11977       }
11978       send_closure_later(G()->notification_manager(), &NotificationManager::remove_notification_group,
11979                          d->message_notification_group.group_id, NotificationId(), d->last_read_inbox_message_id,
11980                          total_count, Slice(source) == Slice("view_messages"), Promise<Unit>());
11981     }
11982 
11983     if (d->mention_notification_group.group_id.is_valid() && d->pinned_message_notification_message_id.is_valid() &&
11984         d->pinned_message_notification_message_id <= d->last_read_inbox_message_id) {
11985       // remove pinned message notification when it is read
11986       remove_dialog_pinned_message_notification(d, source);
11987     }
11988   }
11989 
11990   send_update_chat_read_inbox(d, force_update, source);
11991 }
11992 
set_dialog_last_read_outbox_message_id(Dialog * d,MessageId message_id)11993 void MessagesManager::set_dialog_last_read_outbox_message_id(Dialog *d, MessageId message_id) {
11994   CHECK(!message_id.is_scheduled());
11995 
11996   if (td_->auth_manager_->is_bot()) {
11997     return;
11998   }
11999 
12000   CHECK(d != nullptr);
12001   LOG(INFO) << "Update last read outbox message in " << d->dialog_id << " from " << d->last_read_outbox_message_id
12002             << " to " << message_id;
12003   d->last_read_outbox_message_id = message_id;
12004   d->is_last_read_outbox_message_id_inited = true;
12005   send_update_chat_read_outbox(d);
12006 }
12007 
set_dialog_max_unavailable_message_id(DialogId dialog_id,MessageId max_unavailable_message_id,bool from_update,const char * source)12008 void MessagesManager::set_dialog_max_unavailable_message_id(DialogId dialog_id, MessageId max_unavailable_message_id,
12009                                                             bool from_update, const char *source) {
12010   CHECK(!max_unavailable_message_id.is_scheduled());
12011 
12012   Dialog *d = get_dialog_force(dialog_id, source);
12013   if (d != nullptr) {
12014     if (d->last_new_message_id.is_valid() && max_unavailable_message_id > d->last_new_message_id && from_update) {
12015       if (!td_->auth_manager_->is_bot()) {
12016         LOG(ERROR) << "Tried to set " << dialog_id << " max unavailable message to " << max_unavailable_message_id
12017                    << " from " << source << ", but last new message is " << d->last_new_message_id;
12018       }
12019       max_unavailable_message_id = d->last_new_message_id;
12020     }
12021 
12022     if (d->max_unavailable_message_id == max_unavailable_message_id) {
12023       return;
12024     }
12025 
12026     if (max_unavailable_message_id.is_valid() && max_unavailable_message_id.is_yet_unsent()) {
12027       LOG(ERROR) << "Tried to update " << dialog_id << " last read outbox message with " << max_unavailable_message_id
12028                  << " from " << source;
12029       return;
12030     }
12031     LOG(INFO) << "Set max unavailable message to " << max_unavailable_message_id << " in " << dialog_id << " from "
12032               << source;
12033 
12034     on_dialog_updated(dialog_id, "set_dialog_max_unavailable_message_id");
12035 
12036     if (d->max_unavailable_message_id > max_unavailable_message_id) {
12037       d->max_unavailable_message_id = max_unavailable_message_id;
12038       return;
12039     }
12040 
12041     d->max_unavailable_message_id = max_unavailable_message_id;
12042 
12043     vector<MessageId> message_ids;
12044     find_old_messages(d->messages.get(), max_unavailable_message_id, message_ids);
12045 
12046     vector<int64> deleted_message_ids;
12047     bool need_update_dialog_pos = false;
12048     for (auto message_id : message_ids) {
12049       if (message_id.is_yet_unsent()) {
12050         continue;
12051       }
12052 
12053       auto m = get_message(d, message_id);
12054       CHECK(m != nullptr);
12055       CHECK(m->message_id <= max_unavailable_message_id);
12056       CHECK(m->message_id == message_id);
12057       auto p =
12058           delete_message(d, message_id, !from_update, &need_update_dialog_pos, "set_dialog_max_unavailable_message_id");
12059       CHECK(p.get() == m);
12060       deleted_message_ids.push_back(p->message_id.get());
12061     }
12062 
12063     if (need_update_dialog_pos) {
12064       send_update_chat_last_message(d, "set_dialog_max_unavailable_message_id");
12065     }
12066 
12067     send_update_delete_messages(dialog_id, std::move(deleted_message_ids), !from_update, false);
12068 
12069     if (d->server_unread_count + d->local_unread_count > 0) {
12070       read_history_inbox(dialog_id, max_unavailable_message_id, -1, "set_dialog_max_unavailable_message_id");
12071     }
12072   } else {
12073     LOG(INFO) << "Receive max unavailable message in unknown " << dialog_id << " from " << source;
12074   }
12075 }
12076 
set_dialog_online_member_count(DialogId dialog_id,int32 online_member_count,bool is_from_server,const char * source)12077 void MessagesManager::set_dialog_online_member_count(DialogId dialog_id, int32 online_member_count, bool is_from_server,
12078                                                      const char *source) {
12079   if (td_->auth_manager_->is_bot()) {
12080     return;
12081   }
12082 
12083   Dialog *d = get_dialog(dialog_id);
12084   if (d == nullptr) {
12085     return;
12086   }
12087 
12088   auto &info = dialog_online_member_counts_[dialog_id];
12089   LOG(INFO) << "Change number of online members from " << info.online_member_count << " to " << online_member_count
12090             << " in " << dialog_id << " from " << source;
12091   bool need_update = d->is_opened && (!info.is_update_sent || info.online_member_count != online_member_count);
12092   info.online_member_count = online_member_count;
12093   info.updated_time = Time::now();
12094 
12095   if (need_update) {
12096     info.is_update_sent = true;
12097     send_update_chat_online_member_count(dialog_id, online_member_count);
12098   }
12099   if (d->is_opened) {
12100     if (is_from_server) {
12101       update_dialog_online_member_count_timeout_.set_timeout_in(dialog_id.get(), ONLINE_MEMBER_COUNT_UPDATE_TIME);
12102     } else {
12103       update_dialog_online_member_count_timeout_.add_timeout_in(dialog_id.get(), ONLINE_MEMBER_COUNT_UPDATE_TIME);
12104     }
12105   }
12106 }
12107 
on_update_dialog_online_member_count_timeout(DialogId dialog_id)12108 void MessagesManager::on_update_dialog_online_member_count_timeout(DialogId dialog_id) {
12109   if (G()->close_flag()) {
12110     return;
12111   }
12112 
12113   LOG(INFO) << "Expired timeout for number of online members in " << dialog_id;
12114   Dialog *d = get_dialog(dialog_id);
12115   CHECK(d != nullptr);
12116   if (!d->is_opened) {
12117     send_update_chat_online_member_count(dialog_id, 0);
12118     return;
12119   }
12120 
12121   if (dialog_id.get_type() == DialogType::Channel && !is_broadcast_channel(dialog_id)) {
12122     auto participant_count = td_->contacts_manager_->get_channel_participant_count(dialog_id.get_channel_id());
12123     if (participant_count == 0 || participant_count >= 195) {
12124       td_->create_handler<GetOnlinesQuery>()->send(dialog_id);
12125     } else {
12126       td_->contacts_manager_->get_channel_participants(dialog_id.get_channel_id(),
12127                                                        td_api::make_object<td_api::supergroupMembersFilterRecent>(),
12128                                                        string(), 0, 200, 200, Auto());
12129     }
12130     return;
12131   }
12132   if (dialog_id.get_type() == DialogType::Chat) {
12133     // we need actual online status state, so we need to reget chat participants
12134     td_->contacts_manager_->repair_chat_participants(dialog_id.get_chat_id());
12135     return;
12136   }
12137 }
12138 
get_message_id(const tl_object_ptr<telegram_api::Message> & message_ptr,bool is_scheduled)12139 MessageId MessagesManager::get_message_id(const tl_object_ptr<telegram_api::Message> &message_ptr, bool is_scheduled) {
12140   switch (message_ptr->get_id()) {
12141     case telegram_api::messageEmpty::ID: {
12142       auto message = static_cast<const telegram_api::messageEmpty *>(message_ptr.get());
12143       return is_scheduled ? MessageId() : MessageId(ServerMessageId(message->id_));
12144     }
12145     case telegram_api::message::ID: {
12146       auto message = static_cast<const telegram_api::message *>(message_ptr.get());
12147       return is_scheduled ? MessageId(ScheduledServerMessageId(message->id_), message->date_)
12148                           : MessageId(ServerMessageId(message->id_));
12149     }
12150     case telegram_api::messageService::ID: {
12151       auto message = static_cast<const telegram_api::messageService *>(message_ptr.get());
12152       return is_scheduled ? MessageId(ScheduledServerMessageId(message->id_), message->date_)
12153                           : MessageId(ServerMessageId(message->id_));
12154     }
12155     default:
12156       UNREACHABLE();
12157       return MessageId();
12158   }
12159 }
12160 
get_message_dialog_id(const tl_object_ptr<telegram_api::Message> & message_ptr)12161 DialogId MessagesManager::get_message_dialog_id(const tl_object_ptr<telegram_api::Message> &message_ptr) {
12162   CHECK(message_ptr != nullptr);
12163   switch (message_ptr->get_id()) {
12164     case telegram_api::messageEmpty::ID: {
12165       auto message = static_cast<const telegram_api::messageEmpty *>(message_ptr.get());
12166       return message->peer_id_ == nullptr ? DialogId() : DialogId(message->peer_id_);
12167     }
12168     case telegram_api::message::ID: {
12169       auto message = static_cast<const telegram_api::message *>(message_ptr.get());
12170       return DialogId(message->peer_id_);
12171     }
12172     case telegram_api::messageService::ID: {
12173       auto message = static_cast<const telegram_api::messageService *>(message_ptr.get());
12174       return DialogId(message->peer_id_);
12175     }
12176     default:
12177       UNREACHABLE();
12178       return DialogId();
12179   }
12180 }
12181 
get_full_message_id(const tl_object_ptr<telegram_api::Message> & message_ptr,bool is_scheduled)12182 FullMessageId MessagesManager::get_full_message_id(const tl_object_ptr<telegram_api::Message> &message_ptr,
12183                                                    bool is_scheduled) {
12184   return {get_message_dialog_id(message_ptr), get_message_id(message_ptr, is_scheduled)};
12185 }
12186 
get_message_date(const tl_object_ptr<telegram_api::Message> & message_ptr)12187 int32 MessagesManager::get_message_date(const tl_object_ptr<telegram_api::Message> &message_ptr) {
12188   switch (message_ptr->get_id()) {
12189     case telegram_api::messageEmpty::ID:
12190       return 0;
12191     case telegram_api::message::ID: {
12192       auto message = static_cast<const telegram_api::message *>(message_ptr.get());
12193       return message->date_;
12194     }
12195     case telegram_api::messageService::ID: {
12196       auto message = static_cast<const telegram_api::messageService *>(message_ptr.get());
12197       return message->date_;
12198     }
12199     default:
12200       UNREACHABLE();
12201       return 0;
12202   }
12203 }
12204 
ttl_read_history(Dialog * d,bool is_outgoing,MessageId from_message_id,MessageId till_message_id,double view_date)12205 void MessagesManager::ttl_read_history(Dialog *d, bool is_outgoing, MessageId from_message_id,
12206                                        MessageId till_message_id, double view_date) {
12207   CHECK(!from_message_id.is_scheduled());
12208   CHECK(!till_message_id.is_scheduled());
12209 
12210   // TODO: protect with log event
12211   suffix_load_till_message_id(d, till_message_id,
12212                               PromiseCreator::lambda([actor_id = actor_id(this), dialog_id = d->dialog_id, is_outgoing,
12213                                                       from_message_id, till_message_id, view_date](Result<Unit>) {
12214                                 send_closure(actor_id, &MessagesManager::ttl_read_history_impl, dialog_id, is_outgoing,
12215                                              from_message_id, till_message_id, view_date);
12216                               }));
12217 }
12218 
ttl_read_history_impl(DialogId dialog_id,bool is_outgoing,MessageId from_message_id,MessageId till_message_id,double view_date)12219 void MessagesManager::ttl_read_history_impl(DialogId dialog_id, bool is_outgoing, MessageId from_message_id,
12220                                             MessageId till_message_id, double view_date) {
12221   CHECK(!from_message_id.is_scheduled());
12222   CHECK(!till_message_id.is_scheduled());
12223 
12224   auto *d = get_dialog(dialog_id);
12225   CHECK(d != nullptr);
12226   auto now = Time::now();
12227   for (auto it = MessagesIterator(d, from_message_id); *it && (*it)->message_id >= till_message_id; --it) {
12228     auto *m = *it;
12229     if (m->is_outgoing == is_outgoing) {
12230       ttl_on_view(d, m, view_date, now);
12231     }
12232   }
12233 }
12234 
ttl_on_view(const Dialog * d,Message * m,double view_date,double now)12235 void MessagesManager::ttl_on_view(const Dialog *d, Message *m, double view_date, double now) {
12236   if (m->ttl > 0 && m->ttl_expires_at == 0 && !m->message_id.is_scheduled() && !m->message_id.is_yet_unsent() &&
12237       !m->is_failed_to_send && !m->is_content_secret) {
12238     m->ttl_expires_at = m->ttl + view_date;
12239     ttl_register_message(d->dialog_id, m, now);
12240     on_message_changed(d, m, true, "ttl_on_view");
12241   }
12242 }
12243 
ttl_on_open(Dialog * d,Message * m,double now,bool is_local_read)12244 bool MessagesManager::ttl_on_open(Dialog *d, Message *m, double now, bool is_local_read) {
12245   CHECK(!m->message_id.is_scheduled());
12246   if (m->ttl > 0 && m->ttl_expires_at == 0) {
12247     if (!is_local_read && d->dialog_id.get_type() != DialogType::SecretChat) {
12248       on_message_ttl_expired(d, m);
12249     } else {
12250       m->ttl_expires_at = m->ttl + now;
12251       ttl_register_message(d->dialog_id, m, now);
12252     }
12253     return true;
12254   }
12255   return false;
12256 }
12257 
ttl_register_message(DialogId dialog_id,const Message * m,double now)12258 void MessagesManager::ttl_register_message(DialogId dialog_id, const Message *m, double now) {
12259   CHECK(m != nullptr);
12260   CHECK(m->ttl_expires_at != 0);
12261   CHECK(!m->message_id.is_scheduled());
12262 
12263   auto it_flag = ttl_nodes_.emplace(dialog_id, m->message_id, false);
12264   CHECK(it_flag.second);
12265   auto it = it_flag.first;
12266 
12267   ttl_heap_.insert(m->ttl_expires_at, it->as_heap_node());
12268   ttl_update_timeout(now);
12269 }
12270 
ttl_period_register_message(DialogId dialog_id,const Message * m,double server_time)12271 void MessagesManager::ttl_period_register_message(DialogId dialog_id, const Message *m, double server_time) {
12272   CHECK(m != nullptr);
12273   CHECK(m->ttl_period != 0);
12274   CHECK(!m->message_id.is_scheduled());
12275 
12276   auto it_flag = ttl_nodes_.emplace(dialog_id, m->message_id, true);
12277   CHECK(it_flag.second);
12278   auto it = it_flag.first;
12279 
12280   auto now = Time::now();
12281   ttl_heap_.insert(now + (m->date + m->ttl_period - server_time), it->as_heap_node());
12282   ttl_update_timeout(now);
12283 }
12284 
ttl_unregister_message(DialogId dialog_id,const Message * m,const char * source)12285 void MessagesManager::ttl_unregister_message(DialogId dialog_id, const Message *m, const char *source) {
12286   if (m->ttl_expires_at == 0) {
12287     return;
12288   }
12289   CHECK(!m->message_id.is_scheduled());
12290 
12291   auto it = ttl_nodes_.find(TtlNode(dialog_id, m->message_id, false));
12292 
12293   // expect m->ttl == 0, but m->ttl_expires_at > 0 from binlog
12294   LOG_CHECK(it != ttl_nodes_.end()) << dialog_id << " " << m->message_id << " " << source << " " << G()->close_flag()
12295                                     << " " << m->ttl << " " << m->ttl_expires_at << " " << Time::now() << " "
12296                                     << m->from_database;
12297 
12298   auto *heap_node = it->as_heap_node();
12299   if (heap_node->in_heap()) {
12300     ttl_heap_.erase(heap_node);
12301   }
12302   ttl_nodes_.erase(it);
12303   ttl_update_timeout(Time::now());
12304 }
12305 
ttl_period_unregister_message(DialogId dialog_id,const Message * m)12306 void MessagesManager::ttl_period_unregister_message(DialogId dialog_id, const Message *m) {
12307   if (m->ttl_period == 0) {
12308     return;
12309   }
12310   CHECK(!m->message_id.is_scheduled());
12311 
12312   auto it = ttl_nodes_.find(TtlNode(dialog_id, m->message_id, true));
12313 
12314   CHECK(it != ttl_nodes_.end());
12315 
12316   auto *heap_node = it->as_heap_node();
12317   if (heap_node->in_heap()) {
12318     ttl_heap_.erase(heap_node);
12319   }
12320   ttl_nodes_.erase(it);
12321   ttl_update_timeout(Time::now());
12322 }
12323 
ttl_loop(double now)12324 void MessagesManager::ttl_loop(double now) {
12325   std::unordered_map<DialogId, std::vector<MessageId>, DialogIdHash> to_delete;
12326   while (!ttl_heap_.empty() && ttl_heap_.top_key() < now) {
12327     TtlNode *ttl_node = TtlNode::from_heap_node(ttl_heap_.pop());
12328     auto full_message_id = ttl_node->full_message_id_;
12329     auto dialog_id = full_message_id.get_dialog_id();
12330     if (dialog_id.get_type() == DialogType::SecretChat || ttl_node->by_ttl_period_) {
12331       to_delete[dialog_id].push_back(full_message_id.get_message_id());
12332     } else {
12333       auto d = get_dialog(dialog_id);
12334       CHECK(d != nullptr);
12335       auto m = get_message(d, full_message_id.get_message_id());
12336       CHECK(m != nullptr);
12337       on_message_ttl_expired(d, m);
12338       on_message_changed(d, m, true, "ttl_loop");
12339     }
12340   }
12341   for (auto &it : to_delete) {
12342     delete_dialog_messages(it.first, it.second, false, true, "ttl_loop");
12343   }
12344   ttl_update_timeout(now);
12345 }
12346 
ttl_update_timeout(double now)12347 void MessagesManager::ttl_update_timeout(double now) {
12348   if (ttl_heap_.empty()) {
12349     if (!ttl_slot_.empty()) {
12350       ttl_slot_.cancel_timeout();
12351     }
12352     return;
12353   }
12354   ttl_slot_.set_event(EventCreator::yield(actor_id()));
12355   ttl_slot_.set_timeout_in(ttl_heap_.top_key() - now);
12356 }
12357 
on_message_ttl_expired(Dialog * d,Message * m)12358 void MessagesManager::on_message_ttl_expired(Dialog *d, Message *m) {
12359   CHECK(d != nullptr);
12360   CHECK(m != nullptr);
12361   CHECK(m->ttl > 0);
12362   CHECK(d->dialog_id.get_type() != DialogType::SecretChat);
12363   ttl_unregister_message(d->dialog_id, m, "on_message_ttl_expired");
12364   unregister_message_content(td_, m->content.get(), {d->dialog_id, m->message_id}, "on_message_ttl_expired");
12365   remove_message_file_sources(d->dialog_id, m);
12366   on_message_ttl_expired_impl(d, m);
12367   register_message_content(td_, m->content.get(), {d->dialog_id, m->message_id}, "on_message_ttl_expired");
12368   send_update_message_content(d, m, true, "on_message_ttl_expired");
12369   // the caller must call on_message_changed
12370 }
12371 
on_message_ttl_expired_impl(Dialog * d,Message * m)12372 void MessagesManager::on_message_ttl_expired_impl(Dialog *d, Message *m) {
12373   CHECK(d != nullptr);
12374   CHECK(m != nullptr);
12375   CHECK(m->message_id.is_valid());
12376   CHECK(m->ttl > 0);
12377   CHECK(d->dialog_id.get_type() != DialogType::SecretChat);
12378   delete_message_files(d->dialog_id, m);
12379   update_expired_message_content(m->content);
12380   m->ttl = 0;
12381   m->ttl_expires_at = 0;
12382   if (m->reply_markup != nullptr) {
12383     if (m->reply_markup->type != ReplyMarkup::Type::InlineKeyboard) {
12384       if (!td_->auth_manager_->is_bot()) {
12385         if (d->reply_markup_message_id == m->message_id) {
12386           set_dialog_reply_markup(d, MessageId());
12387         }
12388       }
12389       m->had_reply_markup = true;
12390     }
12391     m->reply_markup = nullptr;
12392   }
12393   remove_message_notification_id(d, m, true, true);
12394   update_message_contains_unread_mention(d, m, false, "on_message_ttl_expired_impl");
12395   unregister_message_reply(d, m);
12396   m->noforwards = false;
12397   m->contains_mention = false;
12398   m->reply_to_message_id = MessageId();
12399   m->max_reply_media_timestamp = -1;
12400   m->reply_in_dialog_id = DialogId();
12401   m->top_thread_message_id = MessageId();
12402   m->linked_top_thread_message_id = MessageId();
12403   m->is_content_secret = false;
12404 }
12405 
loop()12406 void MessagesManager::loop() {
12407   auto token = get_link_token();
12408   if (token == YieldType::TtlDb) {
12409     ttl_db_loop(G()->server_time());
12410   } else {
12411     ttl_loop(Time::now());
12412   }
12413 }
12414 
12415 class MessagesManager::DialogFiltersLogEvent {
12416  public:
12417   int32 updated_date = 0;
12418   const vector<unique_ptr<DialogFilter>> *server_dialog_filters_in;
12419   const vector<unique_ptr<DialogFilter>> *dialog_filters_in;
12420   vector<unique_ptr<DialogFilter>> server_dialog_filters_out;
12421   vector<unique_ptr<DialogFilter>> dialog_filters_out;
12422 
12423   template <class StorerT>
store(StorerT & storer) const12424   void store(StorerT &storer) const {
12425     td::store(updated_date, storer);
12426     td::store(*server_dialog_filters_in, storer);
12427     td::store(*dialog_filters_in, storer);
12428   }
12429 
12430   template <class ParserT>
parse(ParserT & parser)12431   void parse(ParserT &parser) {
12432     td::parse(updated_date, parser);
12433     td::parse(server_dialog_filters_out, parser);
12434     td::parse(dialog_filters_out, parser);
12435   }
12436 };
12437 
tear_down()12438 void MessagesManager::tear_down() {
12439   parent_.reset();
12440 }
12441 
hangup()12442 void MessagesManager::hangup() {
12443   postponed_channel_updates_.clear();
12444   stop();
12445 }
12446 
start_up()12447 void MessagesManager::start_up() {
12448   init();
12449 }
12450 
create_folders()12451 void MessagesManager::create_folders() {
12452   LOG(INFO) << "Create folders";
12453   dialog_folders_[FolderId::main()].folder_id = FolderId::main();
12454   dialog_folders_[FolderId::archive()].folder_id = FolderId::archive();
12455 
12456   add_dialog_list(DialogListId(FolderId::main()));
12457   add_dialog_list(DialogListId(FolderId::archive()));
12458 }
12459 
init()12460 void MessagesManager::init() {
12461   if (is_inited_) {
12462     return;
12463   }
12464   is_inited_ = true;
12465 
12466   always_wait_for_mailbox();
12467 
12468   start_time_ = Time::now();
12469   last_channel_pts_jump_warning_time_ = start_time_ - 3600;
12470 
12471   bool is_authorized = td_->auth_manager_->is_authorized();
12472   bool was_authorized_user = td_->auth_manager_->was_authorized() && !td_->auth_manager_->is_bot();
12473   if (was_authorized_user) {
12474     create_folders();  // ensure that Main and Archive dialog lists are created
12475   }
12476   if (is_authorized && td_->auth_manager_->is_bot()) {
12477     disable_get_dialog_filter_ = true;
12478   }
12479   authorization_date_ = G()->shared_config().get_option_integer("authorization_date");
12480 
12481   if (was_authorized_user) {
12482     vector<NotificationSettingsScope> scopes{NotificationSettingsScope::Private, NotificationSettingsScope::Group,
12483                                              NotificationSettingsScope::Channel};
12484     for (auto scope : scopes) {
12485       auto notification_settings_string =
12486           G()->td_db()->get_binlog_pmc()->get(get_notification_settings_scope_database_key(scope));
12487       if (!notification_settings_string.empty()) {
12488         auto current_settings = get_scope_notification_settings(scope);
12489         CHECK(current_settings != nullptr);
12490         log_event_parse(*current_settings, notification_settings_string).ensure();
12491 
12492         VLOG(notifications) << "Loaded notification settings in " << scope << ": " << *current_settings;
12493 
12494         schedule_scope_unmute(scope, current_settings->mute_until);
12495 
12496         send_closure(G()->td(), &Td::send_update, get_update_scope_notification_settings_object(scope));
12497       }
12498     }
12499     if (!channels_notification_settings_.is_synchronized && is_authorized) {
12500       channels_notification_settings_ = chats_notification_settings_;
12501       channels_notification_settings_.disable_pinned_message_notifications = false;
12502       channels_notification_settings_.disable_mention_notifications = false;
12503       channels_notification_settings_.is_synchronized = false;
12504       send_get_scope_notification_settings_query(NotificationSettingsScope::Channel, Promise<>());
12505     }
12506   }
12507   G()->td_db()->get_binlog_pmc()->erase("nsfac");
12508 
12509   if (was_authorized_user) {
12510     auto dialog_filters = G()->td_db()->get_binlog_pmc()->get("dialog_filters");
12511     if (!dialog_filters.empty()) {
12512       DialogFiltersLogEvent log_event;
12513       if (log_event_parse(log_event, dialog_filters).is_ok()) {
12514         dialog_filters_updated_date_ = G()->ignore_background_updates() ? 0 : log_event.updated_date;
12515         std::unordered_set<DialogFilterId, DialogFilterIdHash> server_dialog_filter_ids;
12516         for (auto &dialog_filter : log_event.server_dialog_filters_out) {
12517           if (server_dialog_filter_ids.insert(dialog_filter->dialog_filter_id).second) {
12518             server_dialog_filters_.push_back(std::move(dialog_filter));
12519           }
12520         }
12521         for (auto &dialog_filter : log_event.dialog_filters_out) {
12522           add_dialog_filter(std::move(dialog_filter), false, "binlog");
12523         }
12524         LOG(INFO) << "Loaded server chat filters " << get_dialog_filter_ids(server_dialog_filters_)
12525                   << " and local chat filters " << get_dialog_filter_ids(dialog_filters_);
12526       } else {
12527         LOG(ERROR) << "Failed to parse chat filters from binlog";
12528       }
12529     }
12530     send_update_chat_filters();  // always send updateChatFilters
12531   }
12532 
12533   if (G()->parameters().use_message_db && was_authorized_user) {
12534     // erase old keys
12535     G()->td_db()->get_binlog_pmc()->erase("last_server_dialog_date");
12536     G()->td_db()->get_binlog_pmc()->erase("unread_message_count");
12537     G()->td_db()->get_binlog_pmc()->erase("unread_dialog_count");
12538 
12539     auto last_database_server_dialog_dates = G()->td_db()->get_binlog_pmc()->prefix_get("last_server_dialog_date");
12540     for (auto &it : last_database_server_dialog_dates) {
12541       auto r_folder_id = to_integer_safe<int32>(it.first);
12542       if (r_folder_id.is_error()) {
12543         LOG(ERROR) << "Can't parse folder ID from " << it.first;
12544         continue;
12545       }
12546 
12547       string order_str;
12548       string dialog_id_str;
12549       std::tie(order_str, dialog_id_str) = split(it.second);
12550 
12551       auto r_order = to_integer_safe<int64>(order_str);
12552       auto r_dialog_id = to_integer_safe<int64>(dialog_id_str);
12553       if (r_order.is_error() || r_dialog_id.is_error()) {
12554         LOG(ERROR) << "Can't parse " << it.second;
12555       } else {
12556         FolderId folder_id(r_folder_id.ok());
12557         auto *folder = get_dialog_folder(folder_id);
12558         CHECK(folder != nullptr);
12559         DialogDate dialog_date(r_order.ok(), DialogId(r_dialog_id.ok()));
12560         if (folder->last_database_server_dialog_date_ < dialog_date) {
12561           folder->last_database_server_dialog_date_ = dialog_date;
12562         }
12563         LOG(INFO) << "Loaded last_database_server_dialog_date_ " << folder->last_database_server_dialog_date_ << " in "
12564                   << folder_id;
12565       }
12566     }
12567 
12568     auto sponsored_dialog_id_string = G()->td_db()->get_binlog_pmc()->get("sponsored_dialog_id");
12569     if (!sponsored_dialog_id_string.empty()) {
12570       auto dialog_id_source = split(Slice(sponsored_dialog_id_string));
12571       auto r_dialog_id = to_integer_safe<int64>(dialog_id_source.first);
12572       auto r_source = DialogSource::unserialize(dialog_id_source.second);
12573       if (r_dialog_id.is_error() || r_source.is_error()) {
12574         LOG(ERROR) << "Can't parse " << sponsored_dialog_id_string;
12575       } else {
12576         DialogId dialog_id(r_dialog_id.ok());
12577 
12578         const Dialog *d = get_dialog_force(dialog_id, "init");
12579         if (d != nullptr) {
12580           LOG(INFO) << "Loaded sponsored " << dialog_id;
12581           add_sponsored_dialog(d, r_source.move_as_ok());
12582         } else {
12583           LOG(ERROR) << "Can't load " << dialog_id;
12584         }
12585       }
12586     }
12587 
12588     auto pinned_dialog_ids = G()->td_db()->get_binlog_pmc()->prefix_get("pinned_dialog_ids");
12589     for (auto &it : pinned_dialog_ids) {
12590       auto r_folder_id = to_integer_safe<int32>(it.first);
12591       if (r_folder_id.is_error()) {
12592         LOG(ERROR) << "Can't parse folder ID from " << it.first;
12593         continue;
12594       }
12595       FolderId folder_id(r_folder_id.ok());
12596 
12597       auto r_dialog_ids = transform(full_split(Slice(it.second), ','), [](Slice str) -> Result<DialogId> {
12598         TRY_RESULT(dialog_id_int, to_integer_safe<int64>(str));
12599         DialogId dialog_id(dialog_id_int);
12600         if (!dialog_id.is_valid()) {
12601           return Status::Error("Have invalid dialog ID");
12602         }
12603         return dialog_id;
12604       });
12605       if (std::any_of(r_dialog_ids.begin(), r_dialog_ids.end(),
12606                       [](auto &r_dialog_id) { return r_dialog_id.is_error(); })) {
12607         LOG(ERROR) << "Can't parse " << it.second;
12608         reload_pinned_dialogs(DialogListId(folder_id), Auto());
12609       } else {
12610         auto *list = get_dialog_list(DialogListId(folder_id));
12611         CHECK(list != nullptr);
12612         CHECK(list->pinned_dialogs_.empty());
12613         for (auto &r_dialog_id : reversed(r_dialog_ids)) {
12614           auto dialog_id = r_dialog_id.move_as_ok();
12615           auto order = get_next_pinned_dialog_order();
12616           list->pinned_dialogs_.emplace_back(order, dialog_id);
12617           list->pinned_dialog_id_orders_.emplace(dialog_id, order);
12618         }
12619         std::reverse(list->pinned_dialogs_.begin(), list->pinned_dialogs_.end());
12620         list->are_pinned_dialogs_inited_ = true;
12621         update_list_last_pinned_dialog_date(*list);
12622 
12623         LOG(INFO) << "Loaded pinned chats " << list->pinned_dialogs_ << " in " << folder_id;
12624       }
12625     }
12626 
12627     auto unread_message_counts = G()->td_db()->get_binlog_pmc()->prefix_get("unread_message_count");
12628     for (auto &it : unread_message_counts) {
12629       auto r_dialog_list_id = to_integer_safe<int64>(it.first);
12630       if (r_dialog_list_id.is_error()) {
12631         LOG(ERROR) << "Can't parse dialog list ID from " << it.first;
12632         continue;
12633       }
12634       string total_count;
12635       string muted_count;
12636       std::tie(total_count, muted_count) = split(it.second);
12637 
12638       auto r_total_count = to_integer_safe<int32>(total_count);
12639       auto r_muted_count = to_integer_safe<int32>(muted_count);
12640       if (r_total_count.is_error() || r_muted_count.is_error()) {
12641         LOG(ERROR) << "Can't parse " << it.second;
12642       } else {
12643         DialogListId dialog_list_id(r_dialog_list_id.ok());
12644         auto *list = get_dialog_list(dialog_list_id);
12645         if (list != nullptr) {
12646           list->unread_message_total_count_ = r_total_count.ok();
12647           list->unread_message_muted_count_ = r_muted_count.ok();
12648           list->is_message_unread_count_inited_ = true;
12649           send_update_unread_message_count(*list, DialogId(), true, "load unread_message_count", true);
12650         } else {
12651           G()->td_db()->get_binlog_pmc()->erase("unread_message_count" + it.first);
12652         }
12653       }
12654     }
12655 
12656     auto unread_dialog_counts = G()->td_db()->get_binlog_pmc()->prefix_get("unread_dialog_count");
12657     for (auto &it : unread_dialog_counts) {
12658       auto r_dialog_list_id = to_integer_safe<int64>(it.first);
12659       if (r_dialog_list_id.is_error()) {
12660         LOG(ERROR) << "Can't parse dialog list ID from " << it.first;
12661         continue;
12662       }
12663 
12664       auto counts = transform(full_split(Slice(it.second)), [](Slice str) { return to_integer_safe<int32>(str); });
12665       if ((counts.size() != 4 && counts.size() != 6) ||
12666           std::any_of(counts.begin(), counts.end(), [](auto &c) { return c.is_error(); })) {
12667         LOG(ERROR) << "Can't parse " << it.second;
12668       } else {
12669         DialogListId dialog_list_id(r_dialog_list_id.ok());
12670         auto *list = get_dialog_list(dialog_list_id);
12671         if (list != nullptr) {
12672           list->unread_dialog_total_count_ = counts[0].ok();
12673           list->unread_dialog_muted_count_ = counts[1].ok();
12674           list->unread_dialog_marked_count_ = counts[2].ok();
12675           list->unread_dialog_muted_marked_count_ = counts[3].ok();
12676           if (counts.size() == 6) {
12677             list->server_dialog_total_count_ = counts[4].ok();
12678             list->secret_chat_total_count_ = counts[5].ok();
12679           }
12680           if (list->server_dialog_total_count_ == -1) {
12681             repair_server_dialog_total_count(dialog_list_id);
12682           }
12683           if (list->secret_chat_total_count_ == -1) {
12684             repair_secret_chat_total_count(dialog_list_id);
12685           }
12686           list->is_dialog_unread_count_inited_ = true;
12687           send_update_unread_chat_count(*list, DialogId(), true, "load unread_dialog_count", true);
12688         } else {
12689           G()->td_db()->get_binlog_pmc()->erase("unread_dialog_count" + it.first);
12690         }
12691       }
12692     }
12693   } else {
12694     G()->td_db()->get_binlog_pmc()->erase_by_prefix("pinned_dialog_ids");
12695     G()->td_db()->get_binlog_pmc()->erase_by_prefix("last_server_dialog_date");
12696     G()->td_db()->get_binlog_pmc()->erase_by_prefix("unread_message_count");
12697     G()->td_db()->get_binlog_pmc()->erase_by_prefix("unread_dialog_count");
12698     G()->td_db()->get_binlog_pmc()->erase("sponsored_dialog_id");
12699   }
12700   G()->td_db()->get_binlog_pmc()->erase("dialog_pinned_current_order");
12701 
12702   if (G()->parameters().use_message_db) {
12703     ttl_db_loop_start(G()->server_time());
12704   }
12705 
12706   load_calls_db_state();
12707 
12708   if (was_authorized_user && is_authorized) {
12709     if (need_synchronize_dialog_filters()) {
12710       reload_dialog_filters();
12711     } else {
12712       auto cache_time = get_dialog_filters_cache_time();
12713       schedule_dialog_filters_reload(cache_time - max(0, G()->unix_time() - dialog_filters_updated_date_));
12714     }
12715   }
12716 
12717   auto auth_notification_ids_string = G()->td_db()->get_binlog_pmc()->get("auth_notification_ids");
12718   if (!auth_notification_ids_string.empty()) {
12719     VLOG(notifications) << "Loaded auth_notification_ids = " << auth_notification_ids_string;
12720     auto ids = full_split(auth_notification_ids_string, ',');
12721     CHECK(ids.size() % 2 == 0);
12722     bool is_changed = false;
12723     auto min_date = G()->unix_time() - AUTH_NOTIFICATION_ID_CACHE_TIME;
12724     for (size_t i = 0; i < ids.size(); i += 2) {
12725       auto date = to_integer_safe<int32>(ids[i + 1]).ok();
12726       if (date < min_date) {
12727         is_changed = true;
12728         continue;
12729       }
12730       auth_notification_id_date_.emplace(std::move(ids[i]), date);
12731     }
12732     if (is_changed) {
12733       save_auth_notification_ids();
12734     }
12735   }
12736 
12737   /*
12738   FI LE *f = std::f open("error.txt", "r");
12739   if (f != nullptr) {
12740     DialogId dialog_id(ChannelId(123456));
12741     force_create_dialog(dialog_id, "test");
12742     Dialog *d = get_dialog(dialog_id);
12743     CHECK(d != nullptr);
12744 
12745     delete_all_dialog_messages(d, true, false);
12746 
12747     d->last_new_message_id = MessageId();
12748     d->last_read_inbox_message_id = MessageId();
12749     d->last_read_outbox_message_id = MessageId();
12750     d->is_last_read_inbox_message_id_inited = false;
12751     d->is_last_read_outbox_message_id_inited = false;
12752 
12753     struct MessageBasicInfo {
12754       MessageId message_id;
12755       bool have_previous;
12756       bool have_next;
12757     };
12758     vector<MessageBasicInfo> messages_info;
12759     std::function<void(Message *m)> get_messages_info = [&](Message *m) {
12760       if (m == nullptr) {
12761         return;
12762       }
12763       get_messages_info(m->left.get());
12764       messages_info.push_back(MessageBasicInfo{m->message_id, m->have_previous, m->have_next});
12765       get_messages_info(m->right.get());
12766     };
12767 
12768     char buf[1280];
12769     while (std::f gets(buf, sizeof(buf), f) != nullptr) {
12770       Slice log_string(buf, std::strlen(buf));
12771       Slice op = log_string.substr(0, log_string.find(' '));
12772       if (op != "MessageOpAdd" && op != "MessageOpDelete") {
12773         LOG(ERROR) << "Unsupported op " << op;
12774         continue;
12775       }
12776       log_string.remove_prefix(log_string.find(' ') + 1);
12777 
12778       if (!begins_with(log_string, "at ")) {
12779         LOG(ERROR) << "Date expected, found " << log_string;
12780         continue;
12781       }
12782       log_string.remove_prefix(3);
12783       auto date_slice = log_string.substr(0, log_string.find(' '));
12784       log_string.remove_prefix(date_slice.size());
12785 
12786       bool is_server = false;
12787       if (begins_with(log_string, " server message ")) {
12788         log_string.remove_prefix(16);
12789         is_server = true;
12790       } else if (begins_with(log_string, " yet unsent message ")) {
12791         log_string.remove_prefix(20);
12792       } else if (begins_with(log_string, " local message ")) {
12793         log_string.remove_prefix(15);
12794       } else {
12795         LOG(ERROR) << "Message identifier expected, found " << log_string;
12796         continue;
12797       }
12798 
12799       auto server_message_id = to_integer<int32>(log_string);
12800       auto add = 0;
12801       if (!is_server) {
12802         log_string.remove_prefix(log_string.find('.') + 1);
12803         add = to_integer<int32>(log_string);
12804       }
12805       log_string.remove_prefix(log_string.find(' ') + 1);
12806 
12807       auto message_id = MessageId(MessageId(ServerMessageId(server_message_id)).get() + add);
12808 
12809       auto content_type = log_string.substr(0, log_string.find(' '));
12810       log_string.remove_prefix(log_string.find(' ') + 1);
12811 
12812       auto read_bool = [](Slice &str) {
12813         if (begins_with(str, "true ")) {
12814           str.remove_prefix(5);
12815           return true;
12816         }
12817         if (begins_with(str, "false ")) {
12818           str.remove_prefix(6);
12819           return false;
12820         }
12821         LOG(ERROR) << "Bool expected, found " << str;
12822         return false;
12823       };
12824 
12825       bool from_update = read_bool(log_string);
12826       bool have_previous = read_bool(log_string);
12827       bool have_next = read_bool(log_string);
12828 
12829       if (op == "MessageOpAdd") {
12830         auto m = make_unique<Message>();
12831         set_message_id(m, message_id);
12832         m->date = G()->unix_time();
12833         m->content = create_text_message_content("text", {}, {});
12834 
12835         m->have_previous = have_previous;
12836         m->have_next = have_next;
12837 
12838         bool need_update = from_update;
12839         bool need_update_dialog_pos = false;
12840         if (add_message_to_dialog(dialog_id, std::move(m), from_update, &need_update, &need_update_dialog_pos,
12841                                   "Unknown source") == nullptr) {
12842           LOG(ERROR) << "Can't add message " << message_id;
12843         }
12844       } else {
12845         bool need_update_dialog_pos = false;
12846         auto m = delete_message(d, message_id, true, &need_update_dialog_pos, "Unknown source");
12847         CHECK(m != nullptr);
12848       }
12849 
12850       messages_info.clear();
12851       get_messages_info(d->messages.get());
12852 
12853       for (size_t i = 0; i + 1 < messages_info.size(); i++) {
12854         if (messages_info[i].have_next != messages_info[i + 1].have_previous) {
12855           LOG(ERROR) << messages_info[i].message_id << " has have_next = " << messages_info[i].have_next << ", but "
12856                      << messages_info[i + 1].message_id
12857                      << " has have_previous = " << messages_info[i + 1].have_previous;
12858         }
12859       }
12860       if (!messages_info.empty()) {
12861         if (messages_info.back().have_next != false) {
12862           LOG(ERROR) << messages_info.back().message_id << " has have_next = true, but there is no next message";
12863         }
12864         if (messages_info[0].have_previous != false) {
12865           LOG(ERROR) << messages_info[0].message_id << " has have_previous = true, but there is no previous message";
12866         }
12867       }
12868     }
12869 
12870     messages_info.clear();
12871     get_messages_info(d->messages.get());
12872     for (auto &info : messages_info) {
12873       bool need_update_dialog_pos = false;
12874       auto m = delete_message(d, info.message_id, true, &need_update_dialog_pos, "Unknown source");
12875       CHECK(m != nullptr);
12876     }
12877 
12878     std::f close(f);
12879   }
12880   */
12881 }
12882 
on_authorization_success()12883 void MessagesManager::on_authorization_success() {
12884   CHECK(td_->auth_manager_->is_authorized());
12885   authorization_date_ = G()->shared_config().get_option_integer("authorization_date");
12886 
12887   if (td_->auth_manager_->is_bot()) {
12888     disable_get_dialog_filter_ = true;
12889     return;
12890   }
12891 
12892   create_folders();
12893 
12894   reload_dialog_filters();
12895 }
12896 
ttl_db_loop_start(double server_now)12897 void MessagesManager::ttl_db_loop_start(double server_now) {
12898   ttl_db_expires_from_ = 0;
12899   ttl_db_expires_till_ = static_cast<int32>(server_now) + 15 /* 15 seconds */;
12900   ttl_db_has_query_ = false;
12901 
12902   ttl_db_loop(server_now);
12903 }
12904 
ttl_db_loop(double server_now)12905 void MessagesManager::ttl_db_loop(double server_now) {
12906   LOG(INFO) << "Begin ttl_db loop: " << tag("expires_from", ttl_db_expires_from_)
12907             << tag("expires_till", ttl_db_expires_till_) << tag("has_query", ttl_db_has_query_);
12908   if (ttl_db_has_query_) {
12909     return;
12910   }
12911 
12912   auto now = static_cast<int32>(server_now);
12913 
12914   if (ttl_db_expires_till_ < 0) {
12915     LOG(INFO) << "Finish ttl_db loop";
12916     return;
12917   }
12918 
12919   if (now < ttl_db_expires_from_) {
12920     ttl_db_slot_.set_event(EventCreator::yield(actor_shared(this, YieldType::TtlDb)));
12921     auto wakeup_in = ttl_db_expires_from_ - server_now;
12922     ttl_db_slot_.set_timeout_in(wakeup_in);
12923     LOG(INFO) << "Set ttl_db timeout in " << wakeup_in;
12924     return;
12925   }
12926 
12927   ttl_db_has_query_ = true;
12928   int32 limit = 50;
12929   LOG(INFO) << "Send ttl_db query " << tag("expires_from", ttl_db_expires_from_)
12930             << tag("expires_till", ttl_db_expires_till_) << tag("limit", limit);
12931   G()->td_db()->get_messages_db_async()->get_expiring_messages(
12932       ttl_db_expires_from_, ttl_db_expires_till_, limit,
12933       PromiseCreator::lambda(
12934           [actor_id = actor_id(this)](Result<std::pair<std::vector<MessagesDbMessage>, int32>> result) {
12935             send_closure(actor_id, &MessagesManager::ttl_db_on_result, std::move(result), false);
12936           }));
12937 }
12938 
ttl_db_on_result(Result<std::pair<std::vector<MessagesDbMessage>,int32>> r_result,bool dummy)12939 void MessagesManager::ttl_db_on_result(Result<std::pair<std::vector<MessagesDbMessage>, int32>> r_result, bool dummy) {
12940   if (G()->close_flag()) {
12941     return;
12942   }
12943 
12944   auto result = r_result.move_as_ok();
12945   ttl_db_has_query_ = false;
12946   ttl_db_expires_from_ = ttl_db_expires_till_;
12947   ttl_db_expires_till_ = result.second;
12948 
12949   LOG(INFO) << "Receive ttl_db query result " << tag("new expires_till", ttl_db_expires_till_)
12950             << tag("got messages", result.first.size());
12951   for (auto &dialog_message : result.first) {
12952     on_get_message_from_database(dialog_message, false, "ttl_db_on_result");
12953   }
12954   ttl_db_loop(G()->server_time());
12955 }
12956 
on_send_secret_message_error(int64 random_id,Status error,Promise<> promise)12957 void MessagesManager::on_send_secret_message_error(int64 random_id, Status error, Promise<> promise) {
12958   promise.set_value(Unit());  // TODO: set after error is saved
12959 
12960   auto it = being_sent_messages_.find(random_id);
12961   if (it != being_sent_messages_.end()) {
12962     auto full_message_id = it->second;
12963     auto *m = get_message(full_message_id);
12964     if (m != nullptr) {
12965       auto file_id = get_message_content_upload_file_id(m->content.get());
12966       if (file_id.is_valid()) {
12967         if (G()->close_flag() && G()->parameters().use_message_db) {
12968           // do not send error, message will be re-sent
12969           return;
12970         }
12971         if (begins_with(error.message(), "FILE_PART_") && ends_with(error.message(), "_MISSING")) {
12972           on_send_message_file_part_missing(random_id, to_integer<int32>(error.message().substr(10)));
12973           return;
12974         }
12975 
12976         if (error.code() != 429 && error.code() < 500 && !G()->close_flag()) {
12977           td_->file_manager_->delete_partial_remote_location(file_id);
12978         }
12979       }
12980     }
12981   }
12982 
12983   on_send_message_fail(random_id, std::move(error));
12984 }
12985 
on_send_secret_message_success(int64 random_id,MessageId message_id,int32 date,unique_ptr<EncryptedFile> file,Promise<> promise)12986 void MessagesManager::on_send_secret_message_success(int64 random_id, MessageId message_id, int32 date,
12987                                                      unique_ptr<EncryptedFile> file, Promise<> promise) {
12988   promise.set_value(Unit());  // TODO: set after message is saved
12989 
12990   FileId new_file_id;
12991   if (file != nullptr) {
12992     if (!DcId::is_valid(file->dc_id_)) {
12993       LOG(ERROR) << "Wrong dc_id = " << file->dc_id_ << " in file " << *file;
12994     } else {
12995       DialogId owner_dialog_id;
12996       auto it = being_sent_messages_.find(random_id);
12997       if (it != being_sent_messages_.end()) {
12998         owner_dialog_id = it->second.get_dialog_id();
12999       }
13000 
13001       new_file_id = td_->file_manager_->register_remote(
13002           FullRemoteFileLocation(FileType::Encrypted, file->id_, file->access_hash_, DcId::internal(file->dc_id_), ""),
13003           FileLocationSource::FromServer, owner_dialog_id, 0, file->size_, to_string(static_cast<uint64>(file->id_)));
13004     }
13005   }
13006 
13007   on_send_message_success(random_id, message_id, date, 0, new_file_id, "process send_secret_message_success");
13008 }
13009 
delete_secret_messages(SecretChatId secret_chat_id,std::vector<int64> random_ids,Promise<> promise)13010 void MessagesManager::delete_secret_messages(SecretChatId secret_chat_id, std::vector<int64> random_ids,
13011                                              Promise<> promise) {
13012   LOG(DEBUG) << "On delete messages in " << secret_chat_id << " with random_ids " << random_ids;
13013   CHECK(secret_chat_id.is_valid());
13014 
13015   DialogId dialog_id(secret_chat_id);
13016   if (!have_dialog_force(dialog_id, "delete_secret_messages")) {
13017     LOG(ERROR) << "Ignore delete secret messages in unknown " << dialog_id;
13018     promise.set_value(Unit());
13019     return;
13020   }
13021 
13022   auto pending_secret_message = make_unique<PendingSecretMessage>();
13023   pending_secret_message->success_promise = std::move(promise);
13024   pending_secret_message->type = PendingSecretMessage::Type::DeleteMessages;
13025   pending_secret_message->dialog_id = dialog_id;
13026   pending_secret_message->random_ids = std::move(random_ids);
13027 
13028   add_secret_message(std::move(pending_secret_message));
13029 }
13030 
finish_delete_secret_messages(DialogId dialog_id,std::vector<int64> random_ids,Promise<> promise)13031 void MessagesManager::finish_delete_secret_messages(DialogId dialog_id, std::vector<int64> random_ids,
13032                                                     Promise<> promise) {
13033   LOG(INFO) << "Delete messages with random_ids " << random_ids << " in " << dialog_id;
13034   promise.set_value(Unit());  // TODO: set after event is saved
13035 
13036   Dialog *d = get_dialog(dialog_id);
13037   CHECK(d != nullptr);
13038   vector<MessageId> to_delete_message_ids;
13039   for (auto &random_id : random_ids) {
13040     auto message_id = get_message_id_by_random_id(d, random_id, "delete_secret_messages");
13041     if (!message_id.is_valid()) {
13042       LOG(INFO) << "Can't find message with random_id " << random_id;
13043       continue;
13044     }
13045     const Message *m = get_message(d, message_id);
13046     CHECK(m != nullptr);
13047     if (!is_service_message_content(m->content->get_type())) {
13048       to_delete_message_ids.push_back(message_id);
13049     } else {
13050       LOG(INFO) << "Skip deletion of service " << message_id;
13051     }
13052   }
13053   delete_dialog_messages(dialog_id, to_delete_message_ids, true, false, "finish_delete_secret_messages");
13054 }
13055 
delete_secret_chat_history(SecretChatId secret_chat_id,bool remove_from_dialog_list,MessageId last_message_id,Promise<> promise)13056 void MessagesManager::delete_secret_chat_history(SecretChatId secret_chat_id, bool remove_from_dialog_list,
13057                                                  MessageId last_message_id, Promise<> promise) {
13058   LOG(DEBUG) << "Delete history in " << secret_chat_id << " up to " << last_message_id;
13059   CHECK(secret_chat_id.is_valid());
13060   CHECK(!last_message_id.is_scheduled());
13061 
13062   DialogId dialog_id(secret_chat_id);
13063   if (!have_dialog_force(dialog_id, "delete_secret_chat_history")) {
13064     LOG(ERROR) << "Ignore delete history in unknown " << dialog_id;
13065     promise.set_value(Unit());
13066     return;
13067   }
13068 
13069   auto pending_secret_message = make_unique<PendingSecretMessage>();
13070   pending_secret_message->success_promise = std::move(promise);
13071   pending_secret_message->type = PendingSecretMessage::Type::DeleteHistory;
13072   pending_secret_message->dialog_id = dialog_id;
13073   pending_secret_message->last_message_id = last_message_id;
13074   pending_secret_message->remove_from_dialog_list = remove_from_dialog_list;
13075 
13076   add_secret_message(std::move(pending_secret_message));
13077 }
13078 
finish_delete_secret_chat_history(DialogId dialog_id,bool remove_from_dialog_list,MessageId last_message_id,Promise<> promise)13079 void MessagesManager::finish_delete_secret_chat_history(DialogId dialog_id, bool remove_from_dialog_list,
13080                                                         MessageId last_message_id, Promise<> promise) {
13081   LOG(DEBUG) << "Delete history in " << dialog_id << " up to " << last_message_id;
13082   Dialog *d = get_dialog(dialog_id);
13083   CHECK(d != nullptr);
13084 
13085   // TODO: probably last_message_id is not needed
13086   delete_all_dialog_messages(d, remove_from_dialog_list, true);
13087   promise.set_value(Unit());  // TODO: set after event is saved
13088 }
13089 
read_secret_chat_outbox(SecretChatId secret_chat_id,int32 up_to_date,int32 read_date)13090 void MessagesManager::read_secret_chat_outbox(SecretChatId secret_chat_id, int32 up_to_date, int32 read_date) {
13091   if (!secret_chat_id.is_valid()) {
13092     LOG(ERROR) << "Receive read secret chat outbox in the invalid " << secret_chat_id;
13093     return;
13094   }
13095   auto dialog_id = DialogId(secret_chat_id);
13096   Dialog *d = get_dialog_force(dialog_id, "read_secret_chat_outbox");
13097   if (d == nullptr) {
13098     return;
13099   }
13100 
13101   if (read_date > 0) {
13102     auto user_id = td_->contacts_manager_->get_secret_chat_user_id(secret_chat_id);
13103     if (user_id.is_valid()) {
13104       td_->contacts_manager_->on_update_user_local_was_online(user_id, read_date);
13105     }
13106   }
13107 
13108   // TODO: protect with log event
13109   suffix_load_till_date(
13110       d, up_to_date,
13111       PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, up_to_date, read_date](Result<Unit> result) {
13112         send_closure(actor_id, &MessagesManager::read_secret_chat_outbox_inner, dialog_id, up_to_date, read_date);
13113       }));
13114 }
13115 
read_secret_chat_outbox_inner(DialogId dialog_id,int32 up_to_date,int32 read_date)13116 void MessagesManager::read_secret_chat_outbox_inner(DialogId dialog_id, int32 up_to_date, int32 read_date) {
13117   Dialog *d = get_dialog(dialog_id);
13118   CHECK(d != nullptr);
13119 
13120   auto end = MessagesConstIterator(d, MessageId::max());
13121   while (*end && (*end)->date > up_to_date) {
13122     --end;
13123   }
13124   if (!*end) {
13125     LOG(INFO) << "Ignore read_secret_chat_outbox in " << dialog_id << " at " << up_to_date
13126               << ": no messages with such date are known";
13127     return;
13128   }
13129   auto max_message_id = (*end)->message_id;
13130   read_history_outbox(dialog_id, max_message_id, read_date);
13131 }
13132 
open_secret_message(SecretChatId secret_chat_id,int64 random_id,Promise<> promise)13133 void MessagesManager::open_secret_message(SecretChatId secret_chat_id, int64 random_id, Promise<> promise) {
13134   promise.set_value(Unit());  // TODO: set after event is saved
13135   DialogId dialog_id(secret_chat_id);
13136   Dialog *d = get_dialog_force(dialog_id, "open_secret_message");
13137   if (d == nullptr) {
13138     LOG(ERROR) << "Ignore opening secret chat message in unknown " << dialog_id;
13139     return;
13140   }
13141 
13142   auto message_id = get_message_id_by_random_id(d, random_id, "open_secret_message");
13143   if (!message_id.is_valid()) {
13144     return;
13145   }
13146   Message *m = get_message(d, message_id);
13147   CHECK(m != nullptr);
13148   if (m->message_id.is_yet_unsent() || m->is_failed_to_send || !m->is_outgoing) {
13149     LOG(ERROR) << "Peer has opened wrong " << message_id << " in " << dialog_id;
13150     return;
13151   }
13152 
13153   read_message_content(d, m, false, "open_secret_message");
13154 }
13155 
on_update_secret_chat_state(SecretChatId secret_chat_id,SecretChatState state)13156 void MessagesManager::on_update_secret_chat_state(SecretChatId secret_chat_id, SecretChatState state) {
13157   if (state == SecretChatState::Closed && !td_->auth_manager_->is_bot()) {
13158     DialogId dialog_id(secret_chat_id);
13159     Dialog *d = get_dialog_force(dialog_id, "on_update_secret_chat_state");
13160     if (d != nullptr) {
13161       if (d->new_secret_chat_notification_id.is_valid()) {
13162         remove_new_secret_chat_notification(d, true);
13163       }
13164       if (d->message_notification_group.group_id.is_valid() && get_dialog_pending_notification_count(d, false) == 0 &&
13165           !d->message_notification_group.last_notification_id.is_valid()) {
13166         CHECK(d->message_notification_group.last_notification_date == 0);
13167         d->message_notification_group.try_reuse = true;
13168         d->message_notification_group.is_changed = true;
13169         on_dialog_updated(d->dialog_id, "on_update_secret_chat_state");
13170       }
13171       CHECK(!d->mention_notification_group.group_id.is_valid());  // there can't be unread mentions in secret chats
13172     }
13173   }
13174 }
13175 
on_get_secret_message(SecretChatId secret_chat_id,UserId user_id,MessageId message_id,int32 date,unique_ptr<EncryptedFile> file,tl_object_ptr<secret_api::decryptedMessage> message,Promise<> promise)13176 void MessagesManager::on_get_secret_message(SecretChatId secret_chat_id, UserId user_id, MessageId message_id,
13177                                             int32 date, unique_ptr<EncryptedFile> file,
13178                                             tl_object_ptr<secret_api::decryptedMessage> message, Promise<> promise) {
13179   LOG(DEBUG) << "On get " << to_string(message);
13180   CHECK(message != nullptr);
13181   CHECK(secret_chat_id.is_valid());
13182   CHECK(user_id.is_valid());
13183   CHECK(message_id.is_valid());
13184   CHECK(date > 0);
13185 
13186   auto pending_secret_message = make_unique<PendingSecretMessage>();
13187   pending_secret_message->success_promise = std::move(promise);
13188   MessageInfo &message_info = pending_secret_message->message_info;
13189   message_info.dialog_id = DialogId(secret_chat_id);
13190   message_info.message_id = message_id;
13191   message_info.sender_user_id = user_id;
13192   message_info.date = date;
13193   message_info.random_id = message->random_id_;
13194   message_info.ttl = message->ttl_;
13195 
13196   Dialog *d = get_dialog_force(message_info.dialog_id, "on_get_secret_message");
13197   if (d == nullptr && have_dialog_info_force(message_info.dialog_id)) {
13198     force_create_dialog(message_info.dialog_id, "on_get_secret_message", true, true);
13199     d = get_dialog(message_info.dialog_id);
13200   }
13201   if (d == nullptr) {
13202     LOG(ERROR) << "Ignore secret message in unknown " << message_info.dialog_id;
13203     pending_secret_message->success_promise.set_error(Status::Error(500, "Chat not found"));
13204     return;
13205   }
13206 
13207   pending_secret_message->load_data_multipromise.add_promise(Auto());
13208   auto lock_promise = pending_secret_message->load_data_multipromise.get_promise();
13209 
13210   int32 flags = MESSAGE_FLAG_HAS_UNREAD_CONTENT | MESSAGE_FLAG_HAS_FROM_ID;
13211   if ((message->flags_ & secret_api::decryptedMessage::REPLY_TO_RANDOM_ID_MASK) != 0) {
13212     message_info.reply_to_message_id = get_message_id_by_random_id(
13213         get_dialog(message_info.dialog_id), message->reply_to_random_id_, "on_get_secret_message");
13214     if (message_info.reply_to_message_id.is_valid()) {
13215       flags |= MESSAGE_FLAG_IS_REPLY;
13216     }
13217   }
13218   if ((message->flags_ & secret_api::decryptedMessage::ENTITIES_MASK) != 0) {
13219     flags |= MESSAGE_FLAG_HAS_ENTITIES;
13220   }
13221   if ((message->flags_ & secret_api::decryptedMessage::MEDIA_MASK) != 0) {
13222     flags |= MESSAGE_FLAG_HAS_MEDIA;
13223   }
13224   if ((message->flags_ & secret_api::decryptedMessage::SILENT_MASK) != 0) {
13225     flags |= MESSAGE_FLAG_IS_SILENT;
13226   }
13227 
13228   if (!clean_input_string(message->via_bot_name_)) {
13229     LOG(WARNING) << "Receive invalid bot username " << message->via_bot_name_;
13230     message->via_bot_name_.clear();
13231   }
13232   if (!message->via_bot_name_.empty()) {
13233     auto request_promise = PromiseCreator::lambda(
13234         [actor_id = actor_id(this), via_bot_username = message->via_bot_name_, message_info_ptr = &message_info,
13235          promise = pending_secret_message->load_data_multipromise.get_promise()](Unit) mutable {
13236           send_closure(actor_id, &MessagesManager::on_resolve_secret_chat_message_via_bot_username, via_bot_username,
13237                        message_info_ptr, std::move(promise));
13238         });
13239     search_public_dialog(message->via_bot_name_, false, std::move(request_promise));
13240   }
13241   if ((message->flags_ & secret_api::decryptedMessage::GROUPED_ID_MASK) != 0 && message->grouped_id_ != 0) {
13242     message_info.media_album_id = message->grouped_id_;
13243     flags |= MESSAGE_FLAG_HAS_MEDIA_ALBUM_ID;
13244   }
13245 
13246   message_info.flags = flags;
13247   message_info.content = get_secret_message_content(
13248       td_, std::move(message->message_), std::move(file), std::move(message->media_), std::move(message->entities_),
13249       message_info.dialog_id, pending_secret_message->load_data_multipromise);
13250 
13251   add_secret_message(std::move(pending_secret_message), std::move(lock_promise));
13252 }
13253 
on_resolve_secret_chat_message_via_bot_username(const string & via_bot_username,MessageInfo * message_info_ptr,Promise<Unit> && promise)13254 void MessagesManager::on_resolve_secret_chat_message_via_bot_username(const string &via_bot_username,
13255                                                                       MessageInfo *message_info_ptr,
13256                                                                       Promise<Unit> &&promise) {
13257   if (!G()->close_flag()) {
13258     auto dialog_id = resolve_dialog_username(via_bot_username);
13259     if (dialog_id.is_valid() && dialog_id.get_type() == DialogType::User) {
13260       auto user_id = dialog_id.get_user_id();
13261       auto r_bot_data = td_->contacts_manager_->get_bot_data(user_id);
13262       if (r_bot_data.is_ok() && r_bot_data.ok().is_inline) {
13263         message_info_ptr->flags |= MESSAGE_FLAG_IS_SENT_VIA_BOT;
13264         message_info_ptr->via_bot_user_id = user_id;
13265       }
13266     }
13267   }
13268   promise.set_value(Unit());
13269 }
13270 
on_secret_chat_screenshot_taken(SecretChatId secret_chat_id,UserId user_id,MessageId message_id,int32 date,int64 random_id,Promise<> promise)13271 void MessagesManager::on_secret_chat_screenshot_taken(SecretChatId secret_chat_id, UserId user_id, MessageId message_id,
13272                                                       int32 date, int64 random_id, Promise<> promise) {
13273   LOG(DEBUG) << "On screenshot taken in " << secret_chat_id;
13274   CHECK(secret_chat_id.is_valid());
13275   CHECK(user_id.is_valid());
13276   CHECK(message_id.is_valid());
13277   CHECK(date > 0);
13278 
13279   auto pending_secret_message = make_unique<PendingSecretMessage>();
13280   pending_secret_message->success_promise = std::move(promise);
13281   MessageInfo &message_info = pending_secret_message->message_info;
13282   message_info.dialog_id = DialogId(secret_chat_id);
13283   message_info.message_id = message_id;
13284   message_info.sender_user_id = user_id;
13285   message_info.date = date;
13286   message_info.random_id = random_id;
13287   message_info.flags = MESSAGE_FLAG_HAS_FROM_ID;
13288   message_info.content = create_screenshot_taken_message_content();
13289 
13290   Dialog *d = get_dialog_force(message_info.dialog_id, "on_secret_chat_screenshot_taken");
13291   if (d == nullptr && have_dialog_info_force(message_info.dialog_id)) {
13292     force_create_dialog(message_info.dialog_id, "on_get_secret_message", true, true);
13293     d = get_dialog(message_info.dialog_id);
13294   }
13295   if (d == nullptr) {
13296     LOG(ERROR) << "Ignore secret message in unknown " << message_info.dialog_id;
13297     pending_secret_message->success_promise.set_error(Status::Error(500, "Chat not found"));
13298     return;
13299   }
13300 
13301   add_secret_message(std::move(pending_secret_message));
13302 }
13303 
on_secret_chat_ttl_changed(SecretChatId secret_chat_id,UserId user_id,MessageId message_id,int32 date,int32 ttl,int64 random_id,Promise<> promise)13304 void MessagesManager::on_secret_chat_ttl_changed(SecretChatId secret_chat_id, UserId user_id, MessageId message_id,
13305                                                  int32 date, int32 ttl, int64 random_id, Promise<> promise) {
13306   LOG(DEBUG) << "On TTL set in " << secret_chat_id << " to " << ttl;
13307   CHECK(secret_chat_id.is_valid());
13308   CHECK(user_id.is_valid());
13309   CHECK(message_id.is_valid());
13310   CHECK(date > 0);
13311   if (ttl < 0) {
13312     LOG(WARNING) << "Receive wrong TTL = " << ttl;
13313     promise.set_value(Unit());
13314     return;
13315   }
13316 
13317   auto pending_secret_message = make_unique<PendingSecretMessage>();
13318   pending_secret_message->success_promise = std::move(promise);
13319   MessageInfo &message_info = pending_secret_message->message_info;
13320   message_info.dialog_id = DialogId(secret_chat_id);
13321   message_info.message_id = message_id;
13322   message_info.sender_user_id = user_id;
13323   message_info.date = date;
13324   message_info.random_id = random_id;
13325   message_info.flags = MESSAGE_FLAG_HAS_FROM_ID;
13326   message_info.content = create_chat_set_ttl_message_content(ttl);
13327 
13328   Dialog *d = get_dialog_force(message_info.dialog_id, "on_secret_chat_ttl_changed");
13329   if (d == nullptr && have_dialog_info_force(message_info.dialog_id)) {
13330     force_create_dialog(message_info.dialog_id, "on_get_secret_message", true, true);
13331     d = get_dialog(message_info.dialog_id);
13332   }
13333   if (d == nullptr) {
13334     LOG(ERROR) << "Ignore secret message in unknown " << message_info.dialog_id;
13335     pending_secret_message->success_promise.set_error(Status::Error(500, "Chat not found"));
13336     return;
13337   }
13338 
13339   add_secret_message(std::move(pending_secret_message));
13340 }
13341 
add_secret_message(unique_ptr<PendingSecretMessage> pending_secret_message,Promise<Unit> lock_promise)13342 void MessagesManager::add_secret_message(unique_ptr<PendingSecretMessage> pending_secret_message,
13343                                          Promise<Unit> lock_promise) {
13344   auto &multipromise = pending_secret_message->load_data_multipromise;
13345   multipromise.set_ignore_errors(true);
13346   int64 token = pending_secret_messages_.add(std::move(pending_secret_message));
13347 
13348   multipromise.add_promise(PromiseCreator::lambda([actor_id = actor_id(this), token](Result<Unit> result) {
13349     if (result.is_ok()) {
13350       send_closure(actor_id, &MessagesManager::on_add_secret_message_ready, token);
13351     }
13352   }));
13353 
13354   if (!lock_promise) {
13355     lock_promise = multipromise.get_promise();
13356   }
13357   lock_promise.set_value(Unit());
13358 }
13359 
on_add_secret_message_ready(int64 token)13360 void MessagesManager::on_add_secret_message_ready(int64 token) {
13361   if (G()->close_flag()) {
13362     return;
13363   }
13364 
13365   pending_secret_messages_.finish(
13366       token, [actor_id = actor_id(this)](unique_ptr<PendingSecretMessage> pending_secret_message) {
13367         send_closure_later(actor_id, &MessagesManager::finish_add_secret_message, std::move(pending_secret_message));
13368       });
13369 }
13370 
finish_add_secret_message(unique_ptr<PendingSecretMessage> pending_secret_message)13371 void MessagesManager::finish_add_secret_message(unique_ptr<PendingSecretMessage> pending_secret_message) {
13372   if (G()->close_flag()) {
13373     return;
13374   }
13375 
13376   if (pending_secret_message->type == PendingSecretMessage::Type::DeleteMessages) {
13377     return finish_delete_secret_messages(pending_secret_message->dialog_id,
13378                                          std::move(pending_secret_message->random_ids),
13379                                          std::move(pending_secret_message->success_promise));
13380   }
13381   if (pending_secret_message->type == PendingSecretMessage::Type::DeleteHistory) {
13382     return finish_delete_secret_chat_history(
13383         pending_secret_message->dialog_id, pending_secret_message->remove_from_dialog_list,
13384         pending_secret_message->last_message_id, std::move(pending_secret_message->success_promise));
13385   }
13386 
13387   auto d = get_dialog(pending_secret_message->message_info.dialog_id);
13388   CHECK(d != nullptr);
13389   auto random_id = pending_secret_message->message_info.random_id;
13390   auto message_id = get_message_id_by_random_id(d, random_id, "finish_add_secret_message");
13391   if (message_id.is_valid()) {
13392     if (message_id != pending_secret_message->message_info.message_id) {
13393       LOG(WARNING) << "Ignore duplicate " << pending_secret_message->message_info.message_id
13394                    << " received earlier with " << message_id << " and random_id " << random_id;
13395     }
13396   } else {
13397     on_get_message(std::move(pending_secret_message->message_info), true, false, true, true,
13398                    "finish add secret message");
13399   }
13400   pending_secret_message->success_promise.set_value(Unit());  // TODO: set after message is saved
13401 }
13402 
parse_telegram_api_message(tl_object_ptr<telegram_api::Message> message_ptr,bool is_scheduled,const char * source) const13403 MessagesManager::MessageInfo MessagesManager::parse_telegram_api_message(
13404     tl_object_ptr<telegram_api::Message> message_ptr, bool is_scheduled, const char *source) const {
13405   LOG(DEBUG) << "Receive from " << source << " " << to_string(message_ptr);
13406   LOG_CHECK(message_ptr != nullptr) << source;
13407 
13408   MessageInfo message_info;
13409   message_info.message_id = get_message_id(message_ptr, is_scheduled);
13410   switch (message_ptr->get_id()) {
13411     case telegram_api::messageEmpty::ID:
13412       message_info.message_id = MessageId();
13413       break;
13414     case telegram_api::message::ID: {
13415       auto message = move_tl_object_as<telegram_api::message>(message_ptr);
13416 
13417       message_info.dialog_id = DialogId(message->peer_id_);
13418       if (message->from_id_ != nullptr) {
13419         message_info.sender_dialog_id = DialogId(message->from_id_);
13420       } else {
13421         message_info.sender_dialog_id = message_info.dialog_id;
13422       }
13423       message_info.date = message->date_;
13424       message_info.forward_header = std::move(message->fwd_from_);
13425       message_info.reply_header = std::move(message->reply_to_);
13426       if (message->flags_ & MESSAGE_FLAG_IS_SENT_VIA_BOT) {
13427         message_info.via_bot_user_id = UserId(message->via_bot_id_);
13428         if (!message_info.via_bot_user_id.is_valid()) {
13429           LOG(ERROR) << "Receive invalid " << message_info.via_bot_user_id << " from " << source;
13430           message_info.via_bot_user_id = UserId();
13431         }
13432       }
13433       if (message->flags_ & MESSAGE_FLAG_HAS_INTERACTION_INFO) {
13434         message_info.view_count = message->views_;
13435         message_info.forward_count = message->forwards_;
13436       }
13437       if (message->flags_ & MESSAGE_FLAG_HAS_REPLY_INFO) {
13438         message_info.reply_info = std::move(message->replies_);
13439       }
13440       if (message->flags_ & MESSAGE_FLAG_HAS_EDIT_DATE) {
13441         message_info.edit_date = message->edit_date_;
13442       }
13443       if (message->flags_ & MESSAGE_FLAG_HAS_MEDIA_ALBUM_ID) {
13444         message_info.media_album_id = message->grouped_id_;
13445       }
13446       if (message->flags_ & MESSAGE_FLAG_HAS_TTL_PERIOD) {
13447         message_info.ttl_period = message->ttl_period_;
13448       }
13449       message_info.flags = message->flags_;
13450       bool is_content_read = (message->flags_ & MESSAGE_FLAG_HAS_UNREAD_CONTENT) == 0;
13451       if (is_message_auto_read(message_info.dialog_id, (message->flags_ & MESSAGE_FLAG_IS_OUT) != 0)) {
13452         is_content_read = true;
13453       }
13454       if (is_scheduled) {
13455         is_content_read = false;
13456       }
13457       auto new_source = PSTRING() << FullMessageId(message_info.dialog_id, message_info.message_id) << " from "
13458                                   << source;
13459       message_info.content = get_message_content(
13460           td_,
13461           get_message_text(td_->contacts_manager_.get(), std::move(message->message_), std::move(message->entities_),
13462                            true, td_->auth_manager_->is_bot(),
13463                            message_info.forward_header ? message_info.forward_header->date_ : message_info.date,
13464                            message_info.media_album_id != 0, new_source.c_str()),
13465           std::move(message->media_), message_info.dialog_id, is_content_read, message_info.via_bot_user_id,
13466           &message_info.ttl, &message_info.disable_web_page_preview);
13467       message_info.reply_markup =
13468           message->flags_ & MESSAGE_FLAG_HAS_REPLY_MARKUP ? std::move(message->reply_markup_) : nullptr;
13469       message_info.restriction_reasons = get_restriction_reasons(std::move(message->restriction_reason_));
13470       message_info.author_signature = std::move(message->post_author_);
13471       break;
13472     }
13473     case telegram_api::messageService::ID: {
13474       auto message = move_tl_object_as<telegram_api::messageService>(message_ptr);
13475 
13476       message_info.dialog_id = DialogId(message->peer_id_);
13477       if (message->from_id_ != nullptr) {
13478         message_info.sender_dialog_id = DialogId(message->from_id_);
13479       } else {
13480         message_info.sender_dialog_id = message_info.dialog_id;
13481       }
13482       message_info.date = message->date_;
13483       if (message->flags_ & MESSAGE_FLAG_HAS_TTL_PERIOD) {
13484         message_info.ttl_period = message->ttl_period_;
13485       }
13486       message_info.flags = message->flags_;
13487 
13488       DialogId reply_in_dialog_id;
13489       MessageId reply_to_message_id;
13490       if (message->reply_to_ != nullptr) {
13491         reply_to_message_id = MessageId(ServerMessageId(message->reply_to_->reply_to_msg_id_));
13492         auto reply_to_peer_id = std::move(message->reply_to_->reply_to_peer_id_);
13493         if (reply_to_peer_id != nullptr) {
13494           reply_in_dialog_id = DialogId(reply_to_peer_id);
13495           if (!reply_in_dialog_id.is_valid()) {
13496             LOG(ERROR) << "Receive reply in invalid " << to_string(reply_to_peer_id);
13497             reply_to_message_id = MessageId();
13498             reply_in_dialog_id = DialogId();
13499           }
13500         }
13501       }
13502       message_info.content = get_action_message_content(td_, std::move(message->action_), message_info.dialog_id,
13503                                                         reply_in_dialog_id, reply_to_message_id);
13504       break;
13505     }
13506     default:
13507       UNREACHABLE();
13508       break;
13509   }
13510   if (message_info.sender_dialog_id.is_valid() && message_info.sender_dialog_id.get_type() == DialogType::User) {
13511     message_info.sender_user_id = message_info.sender_dialog_id.get_user_id();
13512     message_info.sender_dialog_id = DialogId();
13513   }
13514   return message_info;
13515 }
13516 
create_message(MessageInfo && message_info,bool is_channel_message)13517 std::pair<DialogId, unique_ptr<MessagesManager::Message>> MessagesManager::create_message(MessageInfo &&message_info,
13518                                                                                           bool is_channel_message) {
13519   DialogId dialog_id = message_info.dialog_id;
13520   MessageId message_id = message_info.message_id;
13521   if ((!message_id.is_valid() && !message_id.is_valid_scheduled()) || !dialog_id.is_valid()) {
13522     if (message_id != MessageId() || dialog_id != DialogId()) {
13523       LOG(ERROR) << "Receive " << message_id << " in " << dialog_id;
13524     }
13525     return {DialogId(), nullptr};
13526   }
13527   if (message_id.is_yet_unsent() || message_id.is_local()) {
13528     LOG(ERROR) << "Receive " << message_id;
13529     return {DialogId(), nullptr};
13530   }
13531 
13532   CHECK(message_info.content != nullptr);
13533 
13534   auto dialog_type = dialog_id.get_type();
13535   UserId sender_user_id = message_info.sender_user_id;
13536   DialogId sender_dialog_id = message_info.sender_dialog_id;
13537   if (!sender_user_id.is_valid()) {
13538     if (sender_user_id != UserId()) {
13539       LOG(ERROR) << "Receive invalid " << sender_user_id;
13540       sender_user_id = UserId();
13541     }
13542     if (!is_broadcast_channel(dialog_id) && td_->auth_manager_->is_bot()) {
13543       if (dialog_id == sender_dialog_id) {
13544         td_->contacts_manager_->add_anonymous_bot_user();
13545       } else {
13546         td_->contacts_manager_->add_service_notifications_user();
13547       }
13548     }
13549   }
13550   if (sender_dialog_id.is_valid()) {
13551     if (dialog_type == DialogType::User || dialog_type == DialogType::SecretChat) {
13552       LOG(ERROR) << "Receive " << message_id << " sent by " << sender_dialog_id << " in " << dialog_id;
13553       return {DialogId(), nullptr};
13554     }
13555   } else if (sender_dialog_id != DialogId()) {
13556     LOG(ERROR) << "Receive invalid " << sender_dialog_id;
13557     sender_dialog_id = DialogId();
13558   }
13559   if (message_id.is_scheduled()) {
13560     is_channel_message = (dialog_type == DialogType::Channel);
13561   }
13562 
13563   int32 flags = message_info.flags;
13564   bool is_outgoing = (flags & MESSAGE_FLAG_IS_OUT) != 0;
13565   bool is_silent = (flags & MESSAGE_FLAG_IS_SILENT) != 0;
13566   bool is_channel_post = (flags & MESSAGE_FLAG_IS_POST) != 0;
13567   bool is_legacy = (flags & MESSAGE_FLAG_IS_LEGACY) != 0;
13568   bool hide_edit_date = (flags & MESSAGE_FLAG_HIDE_EDIT_DATE) != 0;
13569   bool is_from_scheduled = (flags & MESSAGE_FLAG_IS_FROM_SCHEDULED) != 0;
13570   bool is_pinned = (flags & MESSAGE_FLAG_IS_PINNED) != 0;
13571   bool noforwards = (flags & MESSAGE_FLAG_NOFORWARDS) != 0;
13572 
13573   LOG_IF(ERROR, is_channel_message != (dialog_type == DialogType::Channel))
13574       << "is_channel_message is wrong for " << message_id << " received in the " << dialog_id;
13575   LOG_IF(ERROR, is_channel_post && !is_broadcast_channel(dialog_id))
13576       << "is_channel_post is true for " << message_id << " received in the " << dialog_id;
13577 
13578   UserId my_id = td_->contacts_manager_->get_my_id();
13579   DialogId my_dialog_id = DialogId(my_id);
13580   if (dialog_id == my_dialog_id && (sender_user_id != my_id || sender_dialog_id.is_valid())) {
13581     LOG(ERROR) << "Receive " << sender_user_id << "/" << sender_dialog_id << " as a sender of " << message_id
13582                << " instead of self";
13583     sender_user_id = my_id;
13584     sender_dialog_id = DialogId();
13585   }
13586 
13587   bool supposed_to_be_outgoing = sender_user_id == my_id && !(dialog_id == my_dialog_id && !message_id.is_scheduled());
13588   if (sender_user_id.is_valid() && supposed_to_be_outgoing != is_outgoing) {
13589     LOG(ERROR) << "Receive wrong message out flag: me is " << my_id << ", message is from " << sender_user_id
13590                << ", flags = " << flags << " for " << message_id << " in " << dialog_id;
13591     is_outgoing = supposed_to_be_outgoing;
13592 
13593     /*
13594     // it is useless to call getChannelsDifference, because the channel pts will be increased already
13595     if (dialog_type == DialogType::Channel && !running_get_difference_ && !running_get_channel_difference(dialog_id) &&
13596         get_channel_difference_to_log_event_id_.count(dialog_id) == 0) {
13597       // it is safer to completely ignore the message and re-get it through getChannelsDifference
13598       Dialog *d = get_dialog(dialog_id);
13599       if (d != nullptr) {
13600         channel_get_difference_retry_timeout_.add_timeout_in(dialog_id.get(), 0.001);
13601         return {DialogId(), nullptr};
13602       }
13603     }
13604     */
13605   }
13606 
13607   MessageId reply_to_message_id = message_info.reply_to_message_id;  // for secret messages
13608   DialogId reply_in_dialog_id;
13609   MessageId top_thread_message_id;
13610   if (message_info.reply_header != nullptr) {
13611     reply_to_message_id = MessageId(ServerMessageId(message_info.reply_header->reply_to_msg_id_));
13612     auto reply_to_peer_id = std::move(message_info.reply_header->reply_to_peer_id_);
13613     if (reply_to_peer_id != nullptr) {
13614       reply_in_dialog_id = DialogId(reply_to_peer_id);
13615       if (!reply_in_dialog_id.is_valid()) {
13616         LOG(ERROR) << "Receive reply in invalid " << to_string(reply_to_peer_id);
13617         reply_to_message_id = MessageId();
13618         reply_in_dialog_id = DialogId();
13619       }
13620       if (reply_in_dialog_id == dialog_id) {
13621         reply_in_dialog_id = DialogId();  // just in case
13622       }
13623     }
13624     if (reply_to_message_id.is_valid() && !td_->auth_manager_->is_bot() && !message_id.is_scheduled() &&
13625         !reply_in_dialog_id.is_valid()) {
13626       if ((message_info.reply_header->flags_ & telegram_api::messageReplyHeader::REPLY_TO_TOP_ID_MASK) != 0) {
13627         top_thread_message_id = MessageId(ServerMessageId(message_info.reply_header->reply_to_top_id_));
13628       } else if (!is_broadcast_channel(dialog_id)) {
13629         top_thread_message_id = reply_to_message_id;
13630       }
13631     }
13632   }
13633   fix_server_reply_to_message_id(dialog_id, message_id, reply_in_dialog_id, reply_to_message_id);
13634   fix_server_reply_to_message_id(dialog_id, message_id, reply_in_dialog_id, top_thread_message_id);
13635 
13636   UserId via_bot_user_id = message_info.via_bot_user_id;
13637   if (!via_bot_user_id.is_valid()) {
13638     via_bot_user_id = UserId();
13639   }
13640 
13641   int32 date = message_info.date;
13642   if (date <= 0) {
13643     LOG(ERROR) << "Wrong date = " << date << " received in " << message_id << " in " << dialog_id;
13644     date = 1;
13645   }
13646 
13647   int32 edit_date = message_info.edit_date;
13648   if (edit_date < 0) {
13649     LOG(ERROR) << "Wrong edit_date = " << edit_date << " received in " << message_id << " in " << dialog_id;
13650     edit_date = 0;
13651   }
13652 
13653   auto content_type = message_info.content->get_type();
13654   if (hide_edit_date && td_->auth_manager_->is_bot()) {
13655     hide_edit_date = false;
13656   }
13657   if (hide_edit_date && content_type == MessageContentType::LiveLocation) {
13658     hide_edit_date = false;
13659   }
13660 
13661   int32 ttl_period = message_info.ttl_period;
13662   if (ttl_period < 0 || (message_id.is_scheduled() && ttl_period != 0)) {
13663     LOG(ERROR) << "Wrong TTL period = " << ttl_period << " received in " << message_id << " in " << dialog_id;
13664     ttl_period = 0;
13665   }
13666 
13667   int32 ttl = message_info.ttl;
13668   bool is_content_secret = is_secret_message_content(ttl, content_type);  // must be calculated before TTL is adjusted
13669   if (ttl < 0 || (message_id.is_scheduled() && ttl != 0)) {
13670     LOG(ERROR) << "Wrong TTL = " << ttl << " received in " << message_id << " in " << dialog_id;
13671     ttl = 0;
13672   } else if (ttl > 0) {
13673     ttl = max(ttl, get_message_content_duration(message_info.content.get(), td_) + 1);
13674   }
13675 
13676   int32 view_count = message_info.view_count;
13677   if (view_count < 0) {
13678     LOG(ERROR) << "Wrong view_count = " << view_count << " received in " << message_id << " in " << dialog_id;
13679     view_count = 0;
13680   }
13681   int32 forward_count = message_info.forward_count;
13682   if (forward_count < 0) {
13683     LOG(ERROR) << "Wrong forward_count = " << forward_count << " received in " << message_id << " in " << dialog_id;
13684     forward_count = 0;
13685   }
13686   MessageReplyInfo reply_info(std::move(message_info.reply_info), td_->auth_manager_->is_bot());
13687   if (!top_thread_message_id.is_valid() && !is_broadcast_channel(dialog_id) &&
13688       is_active_message_reply_info(dialog_id, reply_info) && !message_id.is_scheduled()) {
13689     top_thread_message_id = message_id;
13690   }
13691   if (top_thread_message_id.is_valid() && dialog_type != DialogType::Channel) {
13692     top_thread_message_id = MessageId();
13693   }
13694 
13695   bool has_forward_info = message_info.forward_header != nullptr;
13696 
13697   if (sender_dialog_id.is_valid() && sender_dialog_id != dialog_id && have_dialog_info_force(sender_dialog_id)) {
13698     force_create_dialog(sender_dialog_id, "create_message", true);
13699   }
13700 
13701   LOG(INFO) << "Receive " << message_id << " in " << dialog_id << " from " << sender_user_id << "/" << sender_dialog_id;
13702 
13703   auto message = make_unique<Message>();
13704   set_message_id(message, message_id);
13705   message->sender_user_id = sender_user_id;
13706   message->sender_dialog_id = sender_dialog_id;
13707   message->date = date;
13708   message->ttl_period = ttl_period;
13709   message->ttl = ttl;
13710   message->disable_web_page_preview = message_info.disable_web_page_preview;
13711   message->edit_date = edit_date;
13712   message->random_id = message_info.random_id;
13713   message->forward_info = get_message_forward_info(std::move(message_info.forward_header));
13714   message->reply_to_message_id = reply_to_message_id;
13715   message->reply_in_dialog_id = reply_in_dialog_id;
13716   message->top_thread_message_id = top_thread_message_id;
13717   message->via_bot_user_id = via_bot_user_id;
13718   message->restriction_reasons = std::move(message_info.restriction_reasons);
13719   message->author_signature = std::move(message_info.author_signature);
13720   message->is_outgoing = is_outgoing;
13721   message->is_channel_post = is_channel_post;
13722   message->contains_mention =
13723       !is_outgoing && dialog_type != DialogType::User &&
13724       ((flags & MESSAGE_FLAG_HAS_MENTION) != 0 || content_type == MessageContentType::PinMessage);
13725   message->contains_unread_mention =
13726       !message_id.is_scheduled() && message_id.is_server() && message->contains_mention &&
13727       (flags & MESSAGE_FLAG_HAS_UNREAD_CONTENT) != 0 &&
13728       (dialog_type == DialogType::Chat || (dialog_type == DialogType::Channel && !is_broadcast_channel(dialog_id)));
13729   message->disable_notification = is_silent;
13730   message->is_content_secret = is_content_secret;
13731   message->hide_edit_date = hide_edit_date;
13732   message->is_from_scheduled = is_from_scheduled;
13733   message->is_pinned = is_pinned;
13734   message->noforwards = noforwards;
13735   message->view_count = view_count;
13736   message->forward_count = forward_count;
13737   message->reply_info = std::move(reply_info);
13738   message->legacy_layer = (is_legacy ? MTPROTO_LAYER : 0);
13739   message->content = std::move(message_info.content);
13740   message->reply_markup = get_reply_markup(std::move(message_info.reply_markup), td_->auth_manager_->is_bot(), false,
13741                                            message->contains_mention || dialog_type == DialogType::User);
13742 
13743   if (content_type == MessageContentType::ExpiredPhoto || content_type == MessageContentType::ExpiredVideo) {
13744     CHECK(message->ttl == 0);  // TTL is ignored/set to 0 if the message has already been expired
13745     if (message->reply_markup != nullptr) {
13746       if (message->reply_markup->type != ReplyMarkup::Type::InlineKeyboard) {
13747         message->had_reply_markup = true;
13748       }
13749       message->reply_markup = nullptr;
13750     }
13751     message->reply_to_message_id = MessageId();
13752     message->reply_in_dialog_id = DialogId();
13753     message->top_thread_message_id = MessageId();
13754     message->linked_top_thread_message_id = MessageId();
13755   }
13756 
13757   if (message_info.media_album_id != 0) {
13758     if (!is_allowed_media_group_content(content_type)) {
13759       LOG(ERROR) << "Receive media group identifier " << message_info.media_album_id << " in " << message_id << " from "
13760                  << dialog_id << " with content "
13761                  << oneline(to_string(get_message_content_object(message->content.get(), td_, dialog_id, message->date,
13762                                                                  is_content_secret, false, -1)));
13763     } else {
13764       message->media_album_id = message_info.media_album_id;
13765     }
13766   }
13767 
13768   if (message->forward_info == nullptr && has_forward_info) {
13769     message->had_forward_info = true;
13770   }
13771 
13772   return {dialog_id, std::move(message)};
13773 }
13774 
find_old_message_id(DialogId dialog_id,MessageId message_id) const13775 MessageId MessagesManager::find_old_message_id(DialogId dialog_id, MessageId message_id) const {
13776   if (message_id.is_scheduled()) {
13777     CHECK(message_id.is_scheduled_server());
13778     auto dialog_it = update_scheduled_message_ids_.find(dialog_id);
13779     if (dialog_it != update_scheduled_message_ids_.end()) {
13780       auto it = dialog_it->second.find(message_id.get_scheduled_server_message_id());
13781       if (it != dialog_it->second.end()) {
13782         return it->second;
13783       }
13784     }
13785   } else {
13786     CHECK(message_id.is_server());
13787     auto it = update_message_ids_.find(FullMessageId(dialog_id, message_id));
13788     if (it != update_message_ids_.end()) {
13789       return it->second;
13790     }
13791   }
13792   return MessageId();
13793 }
13794 
delete_update_message_id(DialogId dialog_id,MessageId message_id)13795 void MessagesManager::delete_update_message_id(DialogId dialog_id, MessageId message_id) {
13796   if (message_id.is_scheduled()) {
13797     CHECK(message_id.is_scheduled_server());
13798     auto dialog_it = update_scheduled_message_ids_.find(dialog_id);
13799     CHECK(dialog_it != update_scheduled_message_ids_.end());
13800     auto erased_count = dialog_it->second.erase(message_id.get_scheduled_server_message_id());
13801     CHECK(erased_count > 0);
13802     if (dialog_it->second.empty()) {
13803       update_scheduled_message_ids_.erase(dialog_it);
13804     }
13805   } else {
13806     CHECK(message_id.is_server());
13807     auto erased_count = update_message_ids_.erase(FullMessageId(dialog_id, message_id));
13808     CHECK(erased_count > 0);
13809   }
13810 }
13811 
on_get_message(tl_object_ptr<telegram_api::Message> message_ptr,bool from_update,bool is_channel_message,bool is_scheduled,bool have_previous,bool have_next,const char * source)13812 FullMessageId MessagesManager::on_get_message(tl_object_ptr<telegram_api::Message> message_ptr, bool from_update,
13813                                               bool is_channel_message, bool is_scheduled, bool have_previous,
13814                                               bool have_next, const char *source) {
13815   return on_get_message(parse_telegram_api_message(std::move(message_ptr), is_scheduled, source), from_update,
13816                         is_channel_message, have_previous, have_next, source);
13817 }
13818 
on_get_message(MessageInfo && message_info,bool from_update,bool is_channel_message,bool have_previous,bool have_next,const char * source)13819 FullMessageId MessagesManager::on_get_message(MessageInfo &&message_info, bool from_update, bool is_channel_message,
13820                                               bool have_previous, bool have_next, const char *source) {
13821   DialogId dialog_id;
13822   unique_ptr<Message> new_message;
13823   std::tie(dialog_id, new_message) = create_message(std::move(message_info), is_channel_message);
13824   if (new_message == nullptr) {
13825     return FullMessageId();
13826   }
13827   MessageId message_id = new_message->message_id;
13828 
13829   new_message->have_previous = have_previous;
13830   new_message->have_next = have_next;
13831 
13832   bool need_update = from_update;
13833   bool need_update_dialog_pos = false;
13834 
13835   MessageId old_message_id = find_old_message_id(dialog_id, message_id);
13836   bool is_sent_message = false;
13837   if (old_message_id.is_valid() || old_message_id.is_valid_scheduled()) {
13838     LOG(INFO) << "Found temporary " << old_message_id << " for " << FullMessageId{dialog_id, message_id};
13839     Dialog *d = get_dialog(dialog_id);
13840     CHECK(d != nullptr);
13841 
13842     if (!from_update && !message_id.is_scheduled()) {
13843       if (message_id <= d->last_new_message_id) {
13844         if (get_message_force(d, message_id, "receive missed unsent message not from update") != nullptr) {
13845           LOG(ERROR) << "New " << old_message_id << "/" << message_id << " in " << dialog_id << " from " << source
13846                      << " has identifier less than last_new_message_id = " << d->last_new_message_id;
13847           return FullMessageId();
13848         }
13849         // if there is no message yet, then it is likely was missed because of a server bug and is being repaired via
13850         // get_message_from_server from after_get_difference
13851         // TODO move to INFO
13852         LOG(ERROR) << "Receive " << old_message_id << "/" << message_id << " in " << dialog_id << " from " << source
13853                    << " with identifier less than last_new_message_id = " << d->last_new_message_id
13854                    << " and trying to add it anyway";
13855       } else {
13856         // TODO move to INFO
13857         LOG(ERROR) << "Ignore " << old_message_id << "/" << message_id << " received not through update from " << source
13858                    << ": " << oneline(to_string(get_message_object(dialog_id, new_message.get(), "on_get_message")));
13859         if (dialog_id.get_type() == DialogType::Channel && have_input_peer(dialog_id, AccessRights::Read)) {
13860           channel_get_difference_retry_timeout_.add_timeout_in(dialog_id.get(), 0.001);
13861         }
13862         return FullMessageId();
13863       }
13864     }
13865 
13866     delete_update_message_id(dialog_id, message_id);
13867 
13868     if (!new_message->is_outgoing && dialog_id != get_my_dialog_id()) {
13869       // sent message is not from me
13870       LOG(ERROR) << "Sent in " << dialog_id << " " << message_id << " is sent by " << new_message->sender_user_id << "/"
13871                  << new_message->sender_dialog_id;
13872       return FullMessageId();
13873     }
13874 
13875     being_readded_message_id_ = {dialog_id, old_message_id};
13876     unique_ptr<Message> old_message =
13877         delete_message(d, old_message_id, false, &need_update_dialog_pos, "add sent message");
13878     if (old_message == nullptr) {
13879       delete_sent_message_on_server(dialog_id, new_message->message_id);
13880       being_readded_message_id_ = FullMessageId();
13881       return FullMessageId();
13882     }
13883     old_message_id = old_message->message_id;
13884 
13885     need_update = false;
13886 
13887     if (old_message_id.is_valid() && message_id.is_valid() && message_id < old_message_id &&
13888         !can_overflow_message_id(dialog_id)) {
13889       LOG(ERROR) << "Sent " << old_message_id << " to " << dialog_id << " as " << message_id;
13890     }
13891 
13892     set_message_id(new_message, old_message_id);
13893     new_message->from_database = false;
13894     new_message->have_previous = false;
13895     new_message->have_next = false;
13896     update_message(d, old_message.get(), std::move(new_message), &need_update_dialog_pos, false);
13897     new_message = std::move(old_message);
13898 
13899     set_message_id(new_message, message_id);
13900     send_update_message_send_succeeded(d, old_message_id, new_message.get());
13901 
13902     if (!message_id.is_scheduled()) {
13903       is_sent_message = true;
13904     }
13905 
13906     if (!from_update) {
13907       new_message->have_previous = have_previous;
13908       new_message->have_next = have_next;
13909     } else {
13910       new_message->have_previous = true;
13911       new_message->have_next = true;
13912     }
13913   }
13914 
13915   const Message *m = add_message_to_dialog(dialog_id, std::move(new_message), from_update, &need_update,
13916                                            &need_update_dialog_pos, source);
13917   being_readded_message_id_ = FullMessageId();
13918   Dialog *d = get_dialog(dialog_id);
13919   if (m == nullptr) {
13920     if (need_update_dialog_pos && d != nullptr) {
13921       send_update_chat_last_message(d, "on_get_message");
13922     }
13923     if (old_message_id.is_valid() || old_message_id.is_valid_scheduled()) {
13924       CHECK(d != nullptr);
13925       if (!old_message_id.is_valid() || !message_id.is_valid() || old_message_id <= message_id) {
13926         LOG(ERROR) << "Failed to add just sent " << old_message_id << " to " << dialog_id << " as " << message_id
13927                    << " from " << source << ": " << debug_add_message_to_dialog_fail_reason_;
13928       }
13929       send_update_delete_messages(dialog_id, {message_id.get()}, true, false);
13930     }
13931 
13932     return FullMessageId();
13933   }
13934 
13935   CHECK(d != nullptr);
13936 
13937   auto pcc_it = pending_created_dialogs_.find(dialog_id);
13938   if (from_update && pcc_it != pending_created_dialogs_.end()) {
13939     pcc_it->second.set_value(Unit());
13940 
13941     pending_created_dialogs_.erase(pcc_it);
13942   }
13943 
13944   if (need_update) {
13945     send_update_new_message(d, m);
13946   }
13947 
13948   if (is_sent_message) {
13949     try_add_active_live_location(dialog_id, m);
13950 
13951     // add_message_to_dialog will not update counts, because need_update == false
13952     update_message_count_by_index(d, +1, m);
13953   }
13954 
13955   if (is_sent_message || (need_update && !message_id.is_scheduled())) {
13956     update_reply_count_by_message(d, +1, m);
13957     update_forward_count(dialog_id, m);
13958   }
13959 
13960   if (dialog_id.get_type() == DialogType::Channel && !have_input_peer(dialog_id, AccessRights::Read)) {
13961     auto p = delete_message(d, message_id, false, &need_update_dialog_pos, "get a message in inaccessible chat");
13962     CHECK(p.get() == m);
13963     // CHECK(d->messages == nullptr);
13964     send_update_delete_messages(dialog_id, {p->message_id.get()}, false, false);
13965     // don't need to update dialog pos
13966     return FullMessageId();
13967   }
13968 
13969   if (m->message_id.is_scheduled()) {
13970     send_update_chat_has_scheduled_messages(d, false);
13971   }
13972 
13973   if (need_update_dialog_pos) {
13974     send_update_chat_last_message(d, "on_get_message");
13975   }
13976 
13977   // set dialog reply markup only after updateNewMessage and updateChatLastMessage are sent
13978   if (need_update && m->reply_markup != nullptr && !m->message_id.is_scheduled() &&
13979       m->reply_markup->type != ReplyMarkup::Type::InlineKeyboard && m->reply_markup->is_personal &&
13980       !td_->auth_manager_->is_bot()) {
13981     set_dialog_reply_markup(d, message_id);
13982   }
13983 
13984   return FullMessageId(dialog_id, message_id);
13985 }
13986 
set_dialog_last_message_id(Dialog * d,MessageId last_message_id,const char * source)13987 void MessagesManager::set_dialog_last_message_id(Dialog *d, MessageId last_message_id, const char *source) {
13988   CHECK(!last_message_id.is_scheduled());
13989 
13990   LOG(INFO) << "Set " << d->dialog_id << " last message to " << last_message_id << " from " << source;
13991   d->last_message_id = last_message_id;
13992 
13993   if (!last_message_id.is_valid()) {
13994     d->suffix_load_first_message_id_ = MessageId();
13995     d->suffix_load_done_ = false;
13996   }
13997   if (last_message_id.is_valid() && d->delete_last_message_date != 0) {
13998     d->delete_last_message_date = 0;
13999     d->deleted_last_message_id = MessageId();
14000     d->is_last_message_deleted_locally = false;
14001     on_dialog_updated(d->dialog_id, "update_delete_last_message_date");
14002   }
14003   if (d->pending_last_message_date != 0) {
14004     d->pending_last_message_date = 0;
14005     d->pending_last_message_id = MessageId();
14006   }
14007 }
14008 
set_dialog_first_database_message_id(Dialog * d,MessageId first_database_message_id,const char * source)14009 void MessagesManager::set_dialog_first_database_message_id(Dialog *d, MessageId first_database_message_id,
14010                                                            const char *source) {
14011   CHECK(!first_database_message_id.is_scheduled());
14012   if (first_database_message_id == d->first_database_message_id) {
14013     return;
14014   }
14015 
14016   LOG(INFO) << "Set " << d->dialog_id << " first database message to " << first_database_message_id << " from "
14017             << source;
14018   d->first_database_message_id = first_database_message_id;
14019   on_dialog_updated(d->dialog_id, "set_dialog_first_database_message_id");
14020 }
14021 
set_dialog_last_database_message_id(Dialog * d,MessageId last_database_message_id,const char * source,bool is_loaded_from_database)14022 void MessagesManager::set_dialog_last_database_message_id(Dialog *d, MessageId last_database_message_id,
14023                                                           const char *source, bool is_loaded_from_database) {
14024   CHECK(!last_database_message_id.is_scheduled());
14025   if (last_database_message_id == d->last_database_message_id) {
14026     return;
14027   }
14028 
14029   LOG(INFO) << "Set " << d->dialog_id << " last database message to " << last_database_message_id << " from " << source;
14030   d->debug_set_dialog_last_database_message_id = source;
14031   d->last_database_message_id = last_database_message_id;
14032   if (!is_loaded_from_database) {
14033     on_dialog_updated(d->dialog_id, "set_dialog_last_database_message_id");
14034   }
14035 }
14036 
remove_dialog_newer_messages(Dialog * d,MessageId from_message_id,const char * source)14037 void MessagesManager::remove_dialog_newer_messages(Dialog *d, MessageId from_message_id, const char *source) {
14038   LOG(INFO) << "Remove messages in " << d->dialog_id << " newer than " << from_message_id << " from " << source;
14039   CHECK(!d->last_new_message_id.is_valid());
14040 
14041   delete_all_dialog_messages_from_database(d, MessageId::max(), "remove_dialog_newer_messages");
14042   set_dialog_first_database_message_id(d, MessageId(), "remove_dialog_newer_messages");
14043   set_dialog_last_database_message_id(d, MessageId(), source);
14044   if (d->dialog_id.get_type() != DialogType::SecretChat && !d->is_empty) {
14045     d->have_full_history = false;
14046   }
14047   invalidate_message_indexes(d);
14048 
14049   vector<MessageId> to_delete_message_ids;
14050   find_newer_messages(d->messages.get(), from_message_id, to_delete_message_ids);
14051   td::remove_if(to_delete_message_ids, [](MessageId message_id) { return message_id.is_yet_unsent(); });
14052   if (!to_delete_message_ids.empty()) {
14053     LOG(INFO) << "Delete " << format::as_array(to_delete_message_ids) << " newer than " << from_message_id << " in "
14054               << d->dialog_id << " from " << source;
14055 
14056     vector<int64> deleted_message_ids;
14057     bool need_update_dialog_pos = false;
14058     for (auto message_id : to_delete_message_ids) {
14059       auto message = delete_message(d, message_id, false, &need_update_dialog_pos, "remove_dialog_newer_messages");
14060       if (message != nullptr) {
14061         deleted_message_ids.push_back(message->message_id.get());
14062       }
14063     }
14064     if (need_update_dialog_pos) {
14065       send_update_chat_last_message(d, "remove_dialog_newer_messages");
14066     }
14067     send_update_delete_messages(d->dialog_id, std::move(deleted_message_ids), false, false);
14068   }
14069 }
14070 
set_dialog_last_new_message_id(Dialog * d,MessageId last_new_message_id,const char * source)14071 void MessagesManager::set_dialog_last_new_message_id(Dialog *d, MessageId last_new_message_id, const char *source) {
14072   CHECK(!last_new_message_id.is_scheduled());
14073 
14074   LOG_CHECK(last_new_message_id > d->last_new_message_id)
14075       << last_new_message_id << " " << d->last_new_message_id << " " << source;
14076   CHECK(d->dialog_id.get_type() == DialogType::SecretChat || last_new_message_id.is_server());
14077   if (!d->last_new_message_id.is_valid()) {
14078     remove_dialog_newer_messages(d, last_new_message_id, source);
14079 
14080     auto last_new_message = get_message(d, last_new_message_id);
14081     if (last_new_message != nullptr) {
14082       add_message_to_database(d, last_new_message, "set_dialog_last_new_message_id");
14083       set_dialog_first_database_message_id(d, last_new_message_id, "set_dialog_last_new_message_id");
14084       set_dialog_last_database_message_id(d, last_new_message_id, "set_dialog_last_new_message_id");
14085       try_restore_dialog_reply_markup(d, last_new_message);
14086     }
14087   }
14088 
14089   LOG(INFO) << "Set " << d->dialog_id << " last new message to " << last_new_message_id << " from " << source;
14090   d->last_new_message_id = last_new_message_id;
14091   on_dialog_updated(d->dialog_id, source);
14092 }
14093 
set_dialog_last_clear_history_date(Dialog * d,int32 date,MessageId last_clear_history_message_id,const char * source,bool is_loaded_from_database)14094 void MessagesManager::set_dialog_last_clear_history_date(Dialog *d, int32 date, MessageId last_clear_history_message_id,
14095                                                          const char *source, bool is_loaded_from_database) {
14096   CHECK(!last_clear_history_message_id.is_scheduled());
14097 
14098   if (d->last_clear_history_message_id == last_clear_history_message_id && d->last_clear_history_date == date) {
14099     return;
14100   }
14101 
14102   LOG(INFO) << "Set " << d->dialog_id << " last clear history date to " << date << " of "
14103             << last_clear_history_message_id << " from " << source;
14104   if (d->last_clear_history_message_id.is_valid()) {
14105     switch (d->dialog_id.get_type()) {
14106       case DialogType::User:
14107       case DialogType::Chat:
14108         last_clear_history_message_id_to_dialog_id_.erase(d->last_clear_history_message_id);
14109         break;
14110       case DialogType::Channel:
14111       case DialogType::SecretChat:
14112         // nothing to do
14113         break;
14114       case DialogType::None:
14115       default:
14116         UNREACHABLE();
14117     }
14118   }
14119 
14120   d->last_clear_history_date = date;
14121   d->last_clear_history_message_id = last_clear_history_message_id;
14122   if (!is_loaded_from_database) {
14123     on_dialog_updated(d->dialog_id, "set_dialog_last_clear_history_date");
14124   }
14125 
14126   if (d->last_clear_history_message_id.is_valid()) {
14127     switch (d->dialog_id.get_type()) {
14128       case DialogType::User:
14129       case DialogType::Chat:
14130         last_clear_history_message_id_to_dialog_id_[d->last_clear_history_message_id] = d->dialog_id;
14131         break;
14132       case DialogType::Channel:
14133       case DialogType::SecretChat:
14134         // nothing to do
14135         break;
14136       case DialogType::None:
14137       default:
14138         UNREACHABLE();
14139     }
14140   }
14141 }
14142 
set_dialog_unread_mention_count(Dialog * d,int32 unread_mention_count)14143 void MessagesManager::set_dialog_unread_mention_count(Dialog *d, int32 unread_mention_count) {
14144   CHECK(d->unread_mention_count != unread_mention_count);
14145   CHECK(unread_mention_count >= 0);
14146 
14147   d->unread_mention_count = unread_mention_count;
14148   d->message_count_by_index[message_search_filter_index(MessageSearchFilter::UnreadMention)] = unread_mention_count;
14149 }
14150 
set_dialog_is_empty(Dialog * d,const char * source)14151 void MessagesManager::set_dialog_is_empty(Dialog *d, const char *source) {
14152   LOG(INFO) << "Set " << d->dialog_id << " is_empty to true from " << source;
14153   CHECK(d->have_full_history);
14154   d->is_empty = true;
14155 
14156   if (d->server_unread_count + d->local_unread_count > 0) {
14157     MessageId max_message_id =
14158         d->last_database_message_id.is_valid() ? d->last_database_message_id : d->last_new_message_id;
14159     if (max_message_id.is_valid()) {
14160       read_history_inbox(d->dialog_id, max_message_id, -1, "set_dialog_is_empty");
14161     }
14162     if (d->server_unread_count != 0 || d->local_unread_count != 0) {
14163       set_dialog_last_read_inbox_message_id(d, MessageId::min(), 0, 0, true, "set_dialog_is_empty");
14164     }
14165   }
14166   if (d->unread_mention_count > 0) {
14167     set_dialog_unread_mention_count(d, 0);
14168     send_update_chat_unread_mention_count(d);
14169   }
14170   if (d->reply_markup_message_id != MessageId()) {
14171     set_dialog_reply_markup(d, MessageId());
14172   }
14173   std::fill(d->message_count_by_index.begin(), d->message_count_by_index.end(), 0);
14174   d->notification_id_to_message_id.clear();
14175 
14176   if (d->delete_last_message_date != 0) {
14177     if (d->is_last_message_deleted_locally && d->last_clear_history_date == 0) {
14178       set_dialog_last_clear_history_date(d, d->delete_last_message_date, d->deleted_last_message_id,
14179                                          "set_dialog_is_empty");
14180     }
14181     d->delete_last_message_date = 0;
14182     d->deleted_last_message_id = MessageId();
14183     d->is_last_message_deleted_locally = false;
14184 
14185     on_dialog_updated(d->dialog_id, "set_dialog_is_empty");
14186   }
14187   if (d->pending_last_message_date != 0) {
14188     d->pending_last_message_date = 0;
14189     d->pending_last_message_id = MessageId();
14190   }
14191   if (d->last_database_message_id.is_valid()) {
14192     set_dialog_first_database_message_id(d, MessageId(), "set_dialog_is_empty");
14193     set_dialog_last_database_message_id(d, MessageId(), "set_dialog_is_empty");
14194   }
14195 
14196   update_dialog_pos(d, source);
14197 }
14198 
is_dialog_pinned(DialogListId dialog_list_id,DialogId dialog_id) const14199 bool MessagesManager::is_dialog_pinned(DialogListId dialog_list_id, DialogId dialog_id) const {
14200   if (get_dialog_pinned_order(dialog_list_id, dialog_id) != DEFAULT_ORDER) {
14201     return true;
14202   }
14203   if (dialog_list_id.is_filter()) {
14204     const auto *filter = get_dialog_filter(dialog_list_id.get_filter_id());
14205     if (filter != nullptr) {
14206       for (const auto &input_dialog_id : filter->pinned_dialog_ids) {
14207         if (input_dialog_id.get_dialog_id() == dialog_id) {
14208           return true;
14209         }
14210       }
14211     }
14212   }
14213   return false;
14214 }
14215 
get_dialog_pinned_order(DialogListId dialog_list_id,DialogId dialog_id) const14216 int64 MessagesManager::get_dialog_pinned_order(DialogListId dialog_list_id, DialogId dialog_id) const {
14217   return get_dialog_pinned_order(get_dialog_list(dialog_list_id), dialog_id);
14218 }
14219 
get_dialog_pinned_order(const DialogList * list,DialogId dialog_id)14220 int64 MessagesManager::get_dialog_pinned_order(const DialogList *list, DialogId dialog_id) {
14221   if (list != nullptr && !list->pinned_dialog_id_orders_.empty()) {
14222     auto it = list->pinned_dialog_id_orders_.find(dialog_id);
14223     if (it != list->pinned_dialog_id_orders_.end()) {
14224       return it->second;
14225     }
14226   }
14227   return DEFAULT_ORDER;
14228 }
14229 
set_dialog_is_pinned(DialogId dialog_id,bool is_pinned)14230 bool MessagesManager::set_dialog_is_pinned(DialogId dialog_id, bool is_pinned) {
14231   if (td_->auth_manager_->is_bot()) {
14232     return false;
14233   }
14234 
14235   Dialog *d = get_dialog(dialog_id);
14236   CHECK(d != nullptr);
14237   return set_dialog_is_pinned(DialogListId(d->folder_id), d, is_pinned);
14238 }
14239 
14240 // only removes the Dialog from the dialog list, but changes nothing in the corresponding DialogFilter
set_dialog_is_pinned(DialogListId dialog_list_id,Dialog * d,bool is_pinned,bool need_update_dialog_lists)14241 bool MessagesManager::set_dialog_is_pinned(DialogListId dialog_list_id, Dialog *d, bool is_pinned,
14242                                            bool need_update_dialog_lists) {
14243   if (td_->auth_manager_->is_bot()) {
14244     return false;
14245   }
14246 
14247   CHECK(d != nullptr);
14248   if (d->order == DEFAULT_ORDER && is_pinned) {
14249     // the chat can't be pinned
14250     return false;
14251   }
14252 
14253   auto positions = get_dialog_positions(d);
14254   auto *list = get_dialog_list(dialog_list_id);
14255   if (list == nullptr) {
14256     return false;
14257   }
14258   if (!list->are_pinned_dialogs_inited_) {
14259     return false;
14260   }
14261   bool was_pinned = false;
14262   for (size_t pos = 0; pos < list->pinned_dialogs_.size(); pos++) {
14263     auto &pinned_dialog = list->pinned_dialogs_[pos];
14264     if (pinned_dialog.get_dialog_id() == d->dialog_id) {
14265       // the dialog was already pinned
14266       if (is_pinned) {
14267         if (pos == 0) {
14268           return false;
14269         }
14270         auto order = get_next_pinned_dialog_order();
14271         pinned_dialog = DialogDate(order, d->dialog_id);
14272         std::rotate(list->pinned_dialogs_.begin(), list->pinned_dialogs_.begin() + pos,
14273                     list->pinned_dialogs_.begin() + pos + 1);
14274         list->pinned_dialog_id_orders_[d->dialog_id] = order;
14275       } else {
14276         list->pinned_dialogs_.erase(list->pinned_dialogs_.begin() + pos);
14277         list->pinned_dialog_id_orders_.erase(d->dialog_id);
14278       }
14279       was_pinned = true;
14280       break;
14281     }
14282   }
14283   if (!was_pinned) {
14284     if (!is_pinned) {
14285       return false;
14286     }
14287     auto order = get_next_pinned_dialog_order();
14288     list->pinned_dialogs_.insert(list->pinned_dialogs_.begin(), {order, d->dialog_id});
14289     list->pinned_dialog_id_orders_.emplace(d->dialog_id, order);
14290   }
14291 
14292   LOG(INFO) << "Set " << d->dialog_id << " is pinned in " << dialog_list_id << " to " << is_pinned;
14293   if (dialog_list_id.is_folder() && G()->parameters().use_message_db) {
14294     G()->td_db()->get_binlog_pmc()->set(
14295         PSTRING() << "pinned_dialog_ids" << dialog_list_id.get_folder_id().get(),
14296         implode(transform(list->pinned_dialogs_,
14297                           [](auto &pinned_dialog) { return PSTRING() << pinned_dialog.get_dialog_id().get(); }),
14298                 ','));
14299   }
14300 
14301   if (need_update_dialog_lists) {
14302     update_dialog_lists(d, std::move(positions), true, false, "set_dialog_is_pinned");
14303   }
14304   return true;
14305 }
14306 
set_dialog_reply_markup(Dialog * d,MessageId message_id)14307 void MessagesManager::set_dialog_reply_markup(Dialog *d, MessageId message_id) {
14308   if (td_->auth_manager_->is_bot()) {
14309     return;
14310   }
14311 
14312   CHECK(!message_id.is_scheduled());
14313 
14314   if (d->reply_markup_message_id != message_id) {
14315     on_dialog_updated(d->dialog_id, "set_dialog_reply_markup");
14316   }
14317 
14318   d->need_restore_reply_markup = false;
14319 
14320   if (d->reply_markup_message_id.is_valid() || message_id.is_valid()) {
14321     LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in set_dialog_reply_markup";
14322     d->reply_markup_message_id = message_id;
14323     send_closure(G()->td(), &Td::send_update,
14324                  make_tl_object<td_api::updateChatReplyMarkup>(d->dialog_id.get(), message_id.get()));
14325   }
14326 }
14327 
try_restore_dialog_reply_markup(Dialog * d,const Message * m)14328 void MessagesManager::try_restore_dialog_reply_markup(Dialog *d, const Message *m) {
14329   if (!d->need_restore_reply_markup || td_->auth_manager_->is_bot()) {
14330     return;
14331   }
14332 
14333   CHECK(!m->message_id.is_scheduled());
14334   if (m->had_reply_markup) {
14335     LOG(INFO) << "Restore deleted reply markup in " << d->dialog_id;
14336     set_dialog_reply_markup(d, MessageId());
14337   } else if (m->reply_markup != nullptr && m->reply_markup->type != ReplyMarkup::Type::InlineKeyboard &&
14338              m->reply_markup->is_personal) {
14339     LOG(INFO) << "Restore reply markup in " << d->dialog_id << " to " << m->message_id;
14340     set_dialog_reply_markup(d, m->message_id);
14341   }
14342 }
14343 
set_dialog_pinned_message_notification(Dialog * d,MessageId message_id,const char * source)14344 void MessagesManager::set_dialog_pinned_message_notification(Dialog *d, MessageId message_id, const char *source) {
14345   CHECK(d != nullptr);
14346   CHECK(!message_id.is_scheduled());
14347   auto old_message_id = d->pinned_message_notification_message_id;
14348   if (old_message_id == message_id) {
14349     return;
14350   }
14351   VLOG(notifications) << "Change pinned message notification in " << d->dialog_id << " from " << old_message_id
14352                       << " to " << message_id;
14353   if (old_message_id.is_valid()) {
14354     auto m = get_message_force(d, old_message_id, source);
14355     if (m != nullptr && m->notification_id.is_valid() && is_message_notification_active(d, m)) {
14356       // Can't remove pinned_message_notification_message_id  before the call,
14357       // because the notification needs to be still active inside remove_message_notification_id
14358       remove_message_notification_id(d, m, true, false, true);
14359       on_message_changed(d, m, false, source);
14360     } else {
14361       send_closure_later(G()->notification_manager(), &NotificationManager::remove_temporary_notification_by_message_id,
14362                          d->mention_notification_group.group_id, old_message_id, false, source);
14363     }
14364   }
14365   d->pinned_message_notification_message_id = message_id;
14366   on_dialog_updated(d->dialog_id, source);
14367 }
14368 
remove_dialog_pinned_message_notification(Dialog * d,const char * source)14369 void MessagesManager::remove_dialog_pinned_message_notification(Dialog *d, const char *source) {
14370   set_dialog_pinned_message_notification(d, MessageId(), source);
14371 }
14372 
remove_dialog_mention_notifications(Dialog * d)14373 void MessagesManager::remove_dialog_mention_notifications(Dialog *d) {
14374   auto notification_group_id = d->mention_notification_group.group_id;
14375   if (!notification_group_id.is_valid()) {
14376     return;
14377   }
14378   if (d->unread_mention_count == 0) {
14379     return;
14380   }
14381   CHECK(!d->being_added_message_id.is_valid());
14382 
14383   VLOG(notifications) << "Remove mention notifications in " << d->dialog_id;
14384 
14385   vector<MessageId> message_ids;
14386   std::unordered_set<NotificationId, NotificationIdHash> removed_notification_ids_set;
14387   find_messages(d->messages.get(), message_ids, [](const Message *m) { return m->contains_unread_mention; });
14388   VLOG(notifications) << "Found unread mentions in " << message_ids;
14389   for (auto &message_id : message_ids) {
14390     auto m = get_message(d, message_id);
14391     CHECK(m != nullptr);
14392     CHECK(m->message_id.is_valid());
14393     if (m->notification_id.is_valid() && is_message_notification_active(d, m) &&
14394         is_from_mention_notification_group(d, m)) {
14395       removed_notification_ids_set.insert(m->notification_id);
14396     }
14397   }
14398 
14399   message_ids = td_->notification_manager_->get_notification_group_message_ids(notification_group_id);
14400   VLOG(notifications) << "Found active mention notifications in " << message_ids;
14401   for (auto &message_id : message_ids) {
14402     CHECK(!message_id.is_scheduled());
14403     if (message_id != d->pinned_message_notification_message_id) {
14404       auto m = get_message_force(d, message_id, "remove_dialog_mention_notifications");
14405       if (m != nullptr && m->notification_id.is_valid() && is_message_notification_active(d, m)) {
14406         CHECK(is_from_mention_notification_group(d, m));
14407         removed_notification_ids_set.insert(m->notification_id);
14408       }
14409     }
14410   }
14411 
14412   vector<NotificationId> removed_notification_ids(removed_notification_ids_set.begin(),
14413                                                   removed_notification_ids_set.end());
14414   for (size_t i = 0; i < removed_notification_ids.size(); i++) {
14415     send_closure_later(G()->notification_manager(), &NotificationManager::remove_notification, notification_group_id,
14416                        removed_notification_ids[i], false, i + 1 == removed_notification_ids.size(), Promise<Unit>(),
14417                        "remove_dialog_mention_notifications");
14418   }
14419 }
14420 
set_dialog_last_notification(DialogId dialog_id,NotificationGroupInfo & group_info,int32 last_notification_date,NotificationId last_notification_id,const char * source)14421 bool MessagesManager::set_dialog_last_notification(DialogId dialog_id, NotificationGroupInfo &group_info,
14422                                                    int32 last_notification_date, NotificationId last_notification_id,
14423                                                    const char *source) {
14424   if (group_info.last_notification_date != last_notification_date ||
14425       group_info.last_notification_id != last_notification_id) {
14426     VLOG(notifications) << "Set " << group_info.group_id << '/' << dialog_id << " last notification to "
14427                         << last_notification_id << " sent at " << last_notification_date << " from " << source;
14428     group_info.last_notification_date = last_notification_date;
14429     group_info.last_notification_id = last_notification_id;
14430     group_info.is_changed = true;
14431     on_dialog_updated(dialog_id, "set_dialog_last_notification");
14432     return true;
14433   }
14434   return false;
14435 }
14436 
on_update_sent_text_message(int64 random_id,tl_object_ptr<telegram_api::MessageMedia> message_media,vector<tl_object_ptr<telegram_api::MessageEntity>> && entities)14437 void MessagesManager::on_update_sent_text_message(int64 random_id,
14438                                                   tl_object_ptr<telegram_api::MessageMedia> message_media,
14439                                                   vector<tl_object_ptr<telegram_api::MessageEntity>> &&entities) {
14440   int32 message_media_id = message_media == nullptr ? telegram_api::messageMediaEmpty::ID : message_media->get_id();
14441   LOG_IF(ERROR, message_media_id != telegram_api::messageMediaWebPage::ID &&
14442                     message_media_id != telegram_api::messageMediaEmpty::ID)
14443       << "Receive non web-page media for text message: " << oneline(to_string(message_media));
14444 
14445   auto it = being_sent_messages_.find(random_id);
14446   if (it == being_sent_messages_.end()) {
14447     // result of sending message has already been received through getDifference
14448     return;
14449   }
14450 
14451   auto full_message_id = it->second;
14452   auto dialog_id = full_message_id.get_dialog_id();
14453   Dialog *d = get_dialog(dialog_id);
14454   auto m = get_message_force(d, full_message_id.get_message_id(), "on_update_sent_text_message");
14455   if (m == nullptr) {
14456     // message has already been deleted
14457     return;
14458   }
14459   CHECK(m->message_id.is_yet_unsent());
14460   full_message_id = FullMessageId(dialog_id, m->message_id);
14461 
14462   if (m->content->get_type() != MessageContentType::Text) {
14463     LOG(ERROR) << "Text message content has been already changed to " << m->content->get_type();
14464     return;
14465   }
14466 
14467   const FormattedText *old_message_text = get_message_content_text(m->content.get());
14468   CHECK(old_message_text != nullptr);
14469   FormattedText new_message_text = get_message_text(
14470       td_->contacts_manager_.get(), old_message_text->text, std::move(entities), true, td_->auth_manager_->is_bot(),
14471       m->forward_info ? m->forward_info->date : m->date, m->media_album_id != 0, "on_update_sent_text_message");
14472   auto new_content =
14473       get_message_content(td_, std::move(new_message_text), std::move(message_media), dialog_id,
14474                           true /*likely ignored*/, UserId() /*likely ignored*/, nullptr /*ignored*/, nullptr);
14475   if (new_content->get_type() != MessageContentType::Text) {
14476     LOG(ERROR) << "Text message content has changed to " << new_content->get_type();
14477     return;
14478   }
14479 
14480   bool need_update = false;
14481   bool is_content_changed = false;
14482   merge_message_contents(td_, m->content.get(), new_content.get(), need_message_changed_warning(m), dialog_id, false,
14483                          is_content_changed, need_update);
14484 
14485   if (is_content_changed || need_update) {
14486     reregister_message_content(td_, m->content.get(), new_content.get(), full_message_id,
14487                                "on_update_sent_text_message");
14488     m->content = std::move(new_content);
14489     m->is_content_secret = is_secret_message_content(m->ttl, MessageContentType::Text);
14490   }
14491   if (need_update) {
14492     send_update_message_content(dialog_id, m, true, "on_update_sent_text_message");
14493     if (m->message_id == d->last_message_id) {
14494       send_update_chat_last_message_impl(d, "on_update_sent_text_message");
14495     }
14496   }
14497 }
14498 
delete_pending_message_web_page(FullMessageId full_message_id)14499 void MessagesManager::delete_pending_message_web_page(FullMessageId full_message_id) {
14500   auto dialog_id = full_message_id.get_dialog_id();
14501   Dialog *d = get_dialog(dialog_id);
14502   CHECK(d != nullptr);
14503   Message *m = get_message(d, full_message_id.get_message_id());
14504   CHECK(m != nullptr);
14505 
14506   MessageContent *content = m->content.get();
14507   CHECK(has_message_content_web_page(content));
14508   unregister_message_content(td_, content, full_message_id, "delete_pending_message_web_page");
14509   remove_message_content_web_page(content);
14510   register_message_content(td_, content, full_message_id, "delete_pending_message_web_page");
14511 
14512   // don't need to send an updateMessageContent, because the web page was pending
14513 
14514   on_message_changed(d, m, false, "delete_pending_message_web_page");
14515 }
14516 
on_get_dialogs(FolderId folder_id,vector<tl_object_ptr<telegram_api::Dialog>> && dialog_folders,int32 total_count,vector<tl_object_ptr<telegram_api::Message>> && messages,Promise<Unit> && promise)14517 void MessagesManager::on_get_dialogs(FolderId folder_id, vector<tl_object_ptr<telegram_api::Dialog>> &&dialog_folders,
14518                                      int32 total_count, vector<tl_object_ptr<telegram_api::Message>> &&messages,
14519                                      Promise<Unit> &&promise) {
14520   if (td_->updates_manager_->running_get_difference()) {
14521     LOG(INFO) << "Postpone result of getDialogs";
14522     pending_on_get_dialogs_.push_back(PendingOnGetDialogs{folder_id, std::move(dialog_folders), total_count,
14523                                                           std::move(messages), std::move(promise)});
14524     return;
14525   }
14526   bool from_dialog_list = total_count >= 0;
14527   bool from_get_dialog = total_count == -1;
14528   bool from_pinned_dialog_list = total_count == -2;
14529 
14530   if (from_get_dialog && dialog_folders.size() == 1 && dialog_folders[0]->get_id() == telegram_api::dialog::ID) {
14531     DialogId dialog_id(static_cast<const telegram_api::dialog *>(dialog_folders[0].get())->peer_);
14532     if (running_get_channel_difference(dialog_id)) {
14533       LOG(INFO) << "Postpone result of channels getDialogs for " << dialog_id;
14534       pending_channel_on_get_dialogs_.emplace(
14535           dialog_id, PendingOnGetDialogs{folder_id, std::move(dialog_folders), total_count, std::move(messages),
14536                                          std::move(promise)});
14537       return;
14538     }
14539   }
14540 
14541   vector<tl_object_ptr<telegram_api::dialog>> dialogs;
14542   for (auto &dialog_folder : dialog_folders) {
14543     switch (dialog_folder->get_id()) {
14544       case telegram_api::dialog::ID:
14545         dialogs.push_back(telegram_api::move_object_as<telegram_api::dialog>(dialog_folder));
14546         break;
14547       case telegram_api::dialogFolder::ID: {
14548         auto folder = telegram_api::move_object_as<telegram_api::dialogFolder>(dialog_folder);
14549         if (from_pinned_dialog_list) {
14550           // TODO update unread_muted_peers_count:int unread_unmuted_peers_count:int
14551           // unread_muted_messages_count:int unread_unmuted_messages_count:int
14552           FolderId folder_folder_id(folder->folder_->id_);
14553           if (folder_folder_id == FolderId::archive()) {
14554             // archive is expected in pinned dialogs list
14555             break;
14556           }
14557         }
14558         LOG(ERROR) << "Receive unexpected " << to_string(folder);
14559         break;
14560       }
14561       default:
14562         UNREACHABLE();
14563     }
14564   }
14565 
14566   if (from_get_dialog) {
14567     LOG(INFO) << "Process " << dialogs.size() << " chats";
14568   } else if (from_pinned_dialog_list) {
14569     LOG(INFO) << "Process " << dialogs.size() << " pinned chats in " << folder_id;
14570   } else {
14571     LOG(INFO) << "Process " << dialogs.size() << " chats out of " << total_count << " in " << folder_id;
14572   }
14573   std::unordered_map<FullMessageId, DialogDate, FullMessageIdHash> full_message_id_to_dialog_date;
14574   std::unordered_map<FullMessageId, tl_object_ptr<telegram_api::Message>, FullMessageIdHash> full_message_id_to_message;
14575   for (auto &message : messages) {
14576     auto full_message_id = get_full_message_id(message, false);
14577     if (from_dialog_list) {
14578       auto message_date = get_message_date(message);
14579       int64 order = get_dialog_order(full_message_id.get_message_id(), message_date);
14580       full_message_id_to_dialog_date.emplace(full_message_id, DialogDate(order, full_message_id.get_dialog_id()));
14581     }
14582     full_message_id_to_message[full_message_id] = std::move(message);
14583   }
14584 
14585   DialogDate max_dialog_date = MIN_DIALOG_DATE;
14586   for (auto &dialog : dialogs) {
14587     //    LOG(INFO) << to_string(dialog);
14588     DialogId dialog_id(dialog->peer_);
14589     bool has_pts = (dialog->flags_ & DIALOG_FLAG_HAS_PTS) != 0;
14590 
14591     if (!dialog_id.is_valid()) {
14592       LOG(ERROR) << "Receive wrong " << dialog_id;
14593       return promise.set_error(Status::Error(500, "Wrong query result returned: receive wrong chat identifier"));
14594     }
14595     switch (dialog_id.get_type()) {
14596       case DialogType::User:
14597       case DialogType::Chat:
14598         if (has_pts) {
14599           LOG(ERROR) << "Receive user or group " << dialog_id << " with pts";
14600           return promise.set_error(
14601               Status::Error(500, "Wrong query result returned: receive user or basic group chat with pts"));
14602         }
14603         break;
14604       case DialogType::Channel:
14605         if (!has_pts) {
14606           LOG(ERROR) << "Receive channel " << dialog_id << " without pts";
14607           return promise.set_error(
14608               Status::Error(500, "Wrong query result returned: receive supergroup chat without pts"));
14609         }
14610         break;
14611       case DialogType::SecretChat:
14612       case DialogType::None:
14613       default:
14614         UNREACHABLE();
14615         return promise.set_error(Status::Error(500, "UNREACHABLE"));
14616     }
14617 
14618     if (from_dialog_list) {
14619       MessageId last_message_id(ServerMessageId(dialog->top_message_));
14620       if (last_message_id.is_valid()) {
14621         FullMessageId full_message_id(dialog_id, last_message_id);
14622         auto it = full_message_id_to_dialog_date.find(full_message_id);
14623         if (it == full_message_id_to_dialog_date.end()) {
14624           LOG(ERROR) << "Last " << last_message_id << " in " << dialog_id << " not found";
14625           return promise.set_error(Status::Error(500, "Wrong query result returned: last message not found"));
14626         }
14627         FolderId dialog_folder_id((dialog->flags_ & DIALOG_FLAG_HAS_FOLDER_ID) != 0 ? dialog->folder_id_ : 0);
14628         if (dialog_folder_id != folder_id) {
14629           LOG(ERROR) << "Receive " << dialog_id << " in " << dialog_folder_id << " instead of " << folder_id;
14630           continue;
14631         }
14632 
14633         DialogDate dialog_date = it->second;
14634         CHECK(dialog_date.get_dialog_id() == dialog_id);
14635 
14636         if (max_dialog_date < dialog_date) {
14637           max_dialog_date = dialog_date;
14638         }
14639       } else {
14640         LOG(ERROR) << "Receive " << last_message_id << " as last chat message";
14641         continue;
14642       }
14643     }
14644   }
14645 
14646   if (from_dialog_list && total_count < narrow_cast<int32>(dialogs.size())) {
14647     LOG(ERROR) << "Receive chat total_count = " << total_count << ", but " << dialogs.size() << " chats";
14648     total_count = narrow_cast<int32>(dialogs.size());
14649   }
14650 
14651   vector<DialogId> added_dialog_ids;
14652   for (auto &dialog : dialogs) {
14653     MessageId last_message_id(ServerMessageId(dialog->top_message_));
14654     if (!last_message_id.is_valid() && from_dialog_list) {
14655       // skip dialogs without messages
14656       total_count--;
14657       continue;
14658     }
14659 
14660     DialogId dialog_id(dialog->peer_);
14661     if (td::contains(added_dialog_ids, dialog_id)) {
14662       LOG(ERROR) << "Receive " << dialog_id << " twice in result of getChats with total_count = " << total_count;
14663       continue;
14664     }
14665     added_dialog_ids.push_back(dialog_id);
14666     Dialog *d = get_dialog_force(dialog_id, "on_get_dialogs");
14667     bool need_update_dialog_pos = false;
14668     CHECK(!being_added_dialog_id_.is_valid());
14669     being_added_dialog_id_ = dialog_id;
14670     if (d == nullptr) {
14671       d = add_dialog(dialog_id, "on_get_dialogs");
14672       need_update_dialog_pos = true;
14673     } else {
14674       LOG(INFO) << "Receive already created " << dialog_id;
14675       CHECK(d->dialog_id == dialog_id);
14676     }
14677     bool is_new = d->last_new_message_id == MessageId();
14678     auto positions = get_dialog_positions(d);
14679 
14680     set_dialog_folder_id(d, FolderId((dialog->flags_ & DIALOG_FLAG_HAS_FOLDER_ID) != 0 ? dialog->folder_id_ : 0));
14681 
14682     on_update_dialog_notify_settings(dialog_id, std::move(dialog->notify_settings_), "on_get_dialogs");
14683     if (!d->notification_settings.is_synchronized && !td_->auth_manager_->is_bot()) {
14684       LOG(ERROR) << "Failed to synchronize settings in " << dialog_id;
14685       d->notification_settings.is_synchronized = true;
14686       on_dialog_updated(dialog_id, "set notification_settings.is_synchronized");
14687     }
14688 
14689     if (dialog->unread_count_ < 0) {
14690       LOG(ERROR) << "Receive " << dialog->unread_count_ << " as number of unread messages in " << dialog_id;
14691       dialog->unread_count_ = 0;
14692     }
14693     MessageId read_inbox_max_message_id = MessageId(ServerMessageId(dialog->read_inbox_max_id_));
14694     if (!read_inbox_max_message_id.is_valid() && read_inbox_max_message_id != MessageId()) {
14695       LOG(ERROR) << "Receive " << read_inbox_max_message_id << " as last read inbox message in " << dialog_id;
14696       read_inbox_max_message_id = MessageId();
14697     }
14698     MessageId read_outbox_max_message_id = MessageId(ServerMessageId(dialog->read_outbox_max_id_));
14699     if (!read_outbox_max_message_id.is_valid() && read_outbox_max_message_id != MessageId()) {
14700       LOG(ERROR) << "Receive " << read_outbox_max_message_id << " as last read outbox message in " << dialog_id;
14701       read_outbox_max_message_id = MessageId();
14702     }
14703     if (dialog->unread_mentions_count_ < 0) {
14704       LOG(ERROR) << "Receive " << dialog->unread_mentions_count_ << " as number of unread mention messages in "
14705                  << dialog_id;
14706       dialog->unread_mentions_count_ = 0;
14707     }
14708     if (!d->is_is_blocked_inited && !td_->auth_manager_->is_bot()) {
14709       // asynchronously get is_blocked from the server
14710       // TODO add is_blocked to telegram_api::dialog
14711       get_dialog_info_full(dialog_id, Auto(), "on_get_dialogs init is_blocked");
14712     } else if (!d->is_has_bots_inited && !td_->auth_manager_->is_bot()) {
14713       // asynchronously get has_bots from the server
14714       // TODO add has_bots to telegram_api::dialog
14715       get_dialog_info_full(dialog_id, Auto(), "on_get_dialogs init has_bots");
14716     } else if (!d->is_theme_name_inited && !td_->auth_manager_->is_bot()) {
14717       // asynchronously get theme_name from the server
14718       // TODO add theme_name to telegram_api::dialog
14719       get_dialog_info_full(dialog_id, Auto(), "on_get_dialogs init theme_name");
14720     } else if (!d->is_last_pinned_message_id_inited && !td_->auth_manager_->is_bot()) {
14721       // asynchronously get dialog pinned message from the server
14722       get_dialog_pinned_message(dialog_id, Auto());
14723     }
14724 
14725     need_update_dialog_pos |= update_dialog_draft_message(
14726         d, get_draft_message(td_->contacts_manager_.get(), std::move(dialog->draft_)), true, false);
14727     if (is_new) {
14728       bool has_pts = (dialog->flags_ & DIALOG_FLAG_HAS_PTS) != 0;
14729       if (last_message_id.is_valid()) {
14730         FullMessageId full_message_id(dialog_id, last_message_id);
14731         auto last_message = std::move(full_message_id_to_message[full_message_id]);
14732         if (last_message == nullptr) {
14733           LOG(ERROR) << "Last " << full_message_id << " not found";
14734         } else if (!has_pts || d->pts == 0 || dialog->pts_ <= d->pts || d->is_channel_difference_finished) {
14735           auto added_full_message_id =
14736               on_get_message(std::move(last_message), false, has_pts, false, false, false, "get chats");
14737           CHECK(d->last_new_message_id == MessageId());
14738           set_dialog_last_new_message_id(d, last_message_id, "on_get_dialogs");
14739           if (d->last_new_message_id > d->last_message_id && added_full_message_id.get_message_id().is_valid()) {
14740             CHECK(added_full_message_id.get_message_id() == d->last_new_message_id);
14741             set_dialog_last_message_id(d, d->last_new_message_id, "on_get_dialogs");
14742             send_update_chat_last_message(d, "on_get_dialogs");
14743           }
14744         } else {
14745           get_channel_difference(dialog_id, d->pts, true, "on_get_dialogs");
14746         }
14747       }
14748 
14749       if (has_pts && !running_get_channel_difference(dialog_id)) {
14750         set_channel_pts(d, dialog->pts_, "get channel");
14751       }
14752     }
14753     bool is_marked_as_unread = dialog->unread_mark_;
14754     if (is_marked_as_unread != d->is_marked_as_unread) {
14755       set_dialog_is_marked_as_unread(d, is_marked_as_unread);
14756     }
14757 
14758     if (need_update_dialog_pos) {
14759       update_dialog_pos(d, "on_get_dialogs");
14760     }
14761 
14762     if (!td_->auth_manager_->is_bot() && !from_pinned_dialog_list) {
14763       // set is_pinned only after updating dialog pos to ensure that order is initialized
14764       bool is_pinned = (dialog->flags_ & DIALOG_FLAG_IS_PINNED) != 0;
14765       bool was_pinned = is_dialog_pinned(DialogListId(d->folder_id), dialog_id);
14766       if (is_pinned != was_pinned) {
14767         set_dialog_is_pinned(DialogListId(d->folder_id), d, is_pinned);
14768       }
14769     }
14770 
14771     if (!G()->parameters().use_message_db || is_new || !d->is_last_read_inbox_message_id_inited ||
14772         d->need_repair_server_unread_count) {
14773       if (d->last_read_inbox_message_id.is_valid() && !d->last_read_inbox_message_id.is_server() &&
14774           read_inbox_max_message_id == d->last_read_inbox_message_id.get_prev_server_message_id()) {
14775         read_inbox_max_message_id = d->last_read_inbox_message_id;
14776       }
14777       if (d->need_repair_server_unread_count &&
14778           (d->last_read_inbox_message_id <= read_inbox_max_message_id || !need_unread_counter(d->order) ||
14779            !have_input_peer(dialog_id, AccessRights::Read))) {
14780         LOG(INFO) << "Repaired server unread count in " << dialog_id << " from " << d->last_read_inbox_message_id << "/"
14781                   << d->server_unread_count << " to " << read_inbox_max_message_id << "/" << dialog->unread_count_;
14782         d->need_repair_server_unread_count = false;
14783         on_dialog_updated(dialog_id, "repaired dialog server unread count");
14784       }
14785       if (d->need_repair_server_unread_count) {
14786         auto &previous_message_id = previous_repaired_read_inbox_max_message_id_[dialog_id];
14787         if (previous_message_id >= read_inbox_max_message_id) {
14788           // protect from sending the request in a loop
14789           LOG(ERROR) << "Failed to repair server unread count in " << dialog_id
14790                      << ", because receive read_inbox_max_message_id = " << read_inbox_max_message_id << " after "
14791                      << previous_message_id << ", but messages are read up to " << d->last_read_inbox_message_id;
14792           d->need_repair_server_unread_count = false;
14793           on_dialog_updated(dialog_id, "failed to repair dialog server unread count");
14794         } else {
14795           LOG(INFO) << "Have last_read_inbox_message_id = " << d->last_read_inbox_message_id << ", but received only "
14796                     << read_inbox_max_message_id << " from the server, trying to repair server unread count again";
14797           previous_message_id = read_inbox_max_message_id;
14798           repair_server_unread_count(dialog_id, d->server_unread_count);
14799         }
14800       }
14801       if (!d->need_repair_server_unread_count) {
14802         previous_repaired_read_inbox_max_message_id_.erase(dialog_id);
14803       }
14804       if ((d->server_unread_count != dialog->unread_count_ &&
14805            d->last_read_inbox_message_id == read_inbox_max_message_id) ||
14806           d->last_read_inbox_message_id < read_inbox_max_message_id) {
14807         set_dialog_last_read_inbox_message_id(d, read_inbox_max_message_id, dialog->unread_count_,
14808                                               d->local_unread_count, true, "on_get_dialogs");
14809       }
14810       if (!d->is_last_read_inbox_message_id_inited) {
14811         d->is_last_read_inbox_message_id_inited = true;
14812         on_dialog_updated(dialog_id, "set is_last_read_inbox_message_id_inited");
14813       }
14814     }
14815 
14816     if (!G()->parameters().use_message_db || is_new || !d->is_last_read_outbox_message_id_inited) {
14817       if (d->last_read_outbox_message_id < read_outbox_max_message_id) {
14818         set_dialog_last_read_outbox_message_id(d, read_outbox_max_message_id);
14819       }
14820       if (!d->is_last_read_outbox_message_id_inited) {
14821         d->is_last_read_outbox_message_id_inited = true;
14822         on_dialog_updated(dialog_id, "set is_last_read_outbox_message_id_inited");
14823       }
14824     }
14825 
14826     if (!G()->parameters().use_message_db || is_new) {
14827       if (d->unread_mention_count != dialog->unread_mentions_count_) {
14828         set_dialog_unread_mention_count(d, dialog->unread_mentions_count_);
14829         update_dialog_mention_notification_count(d);
14830         send_update_chat_unread_mention_count(d);
14831       }
14832     }
14833 
14834     being_added_dialog_id_ = DialogId();
14835 
14836     update_dialog_lists(d, std::move(positions), true, false, "on_get_dialogs");
14837   }
14838 
14839   if (from_dialog_list) {
14840     CHECK(!td_->auth_manager_->is_bot());
14841     CHECK(total_count >= 0);
14842 
14843     auto &folder_list = add_dialog_list(DialogListId(folder_id));
14844     if (folder_list.server_dialog_total_count_ != total_count) {
14845       auto old_dialog_total_count = get_dialog_total_count(folder_list);
14846       folder_list.server_dialog_total_count_ = total_count;
14847       if (folder_list.is_dialog_unread_count_inited_) {
14848         if (old_dialog_total_count != get_dialog_total_count(folder_list)) {
14849           send_update_unread_chat_count(folder_list, DialogId(), true, "on_get_dialogs");
14850         } else {
14851           save_unread_chat_count(folder_list);
14852         }
14853       }
14854     }
14855 
14856     auto *folder = get_dialog_folder(folder_id);
14857     CHECK(folder != nullptr);
14858     if (dialogs.empty()) {
14859       // if there are no more dialogs on the server
14860       max_dialog_date = MAX_DIALOG_DATE;
14861     }
14862     if (folder->last_server_dialog_date_ < max_dialog_date) {
14863       folder->last_server_dialog_date_ = max_dialog_date;
14864       update_last_dialog_date(folder_id);
14865     } else if (promise) {
14866       LOG(ERROR) << "Last server dialog date didn't increased from " << folder->last_server_dialog_date_ << " to "
14867                  << max_dialog_date << " after receiving " << dialogs.size() << " chats " << added_dialog_ids
14868                  << " from " << total_count << " in " << folder_id
14869                  << ". last_dialog_date = " << folder->folder_last_dialog_date_
14870                  << ", last_loaded_database_dialog_date = " << folder->last_loaded_database_dialog_date_;
14871     }
14872   }
14873   if (from_pinned_dialog_list) {
14874     CHECK(!td_->auth_manager_->is_bot());
14875     auto *folder_list = get_dialog_list(DialogListId(folder_id));
14876     CHECK(folder_list != nullptr);
14877     auto pinned_dialog_ids = remove_secret_chat_dialog_ids(get_pinned_dialog_ids(DialogListId(folder_id)));
14878     bool are_pinned_dialogs_saved = folder_list->are_pinned_dialogs_inited_;
14879     folder_list->are_pinned_dialogs_inited_ = true;
14880     if (pinned_dialog_ids != added_dialog_ids) {
14881       LOG(INFO) << "Update pinned chats order from " << format::as_array(pinned_dialog_ids) << " to "
14882                 << format::as_array(added_dialog_ids);
14883       std::unordered_set<DialogId, DialogIdHash> old_pinned_dialog_ids(pinned_dialog_ids.begin(),
14884                                                                        pinned_dialog_ids.end());
14885 
14886       std::reverse(pinned_dialog_ids.begin(), pinned_dialog_ids.end());
14887       std::reverse(added_dialog_ids.begin(), added_dialog_ids.end());
14888       auto old_it = pinned_dialog_ids.begin();
14889       for (auto dialog_id : added_dialog_ids) {
14890         old_pinned_dialog_ids.erase(dialog_id);
14891         while (old_it < pinned_dialog_ids.end()) {
14892           if (*old_it == dialog_id) {
14893             break;
14894           }
14895           ++old_it;
14896         }
14897         if (old_it < pinned_dialog_ids.end()) {
14898           // leave dialog where it is
14899           ++old_it;
14900           continue;
14901         }
14902         if (set_dialog_is_pinned(dialog_id, true)) {
14903           are_pinned_dialogs_saved = true;
14904         }
14905       }
14906       for (auto dialog_id : old_pinned_dialog_ids) {
14907         Dialog *d = get_dialog_force(dialog_id, "on_get_dialogs pinned");
14908         if (d == nullptr) {
14909           LOG(ERROR) << "Failed to find " << dialog_id << " to unpin in " << folder_id;
14910           force_create_dialog(dialog_id, "from_pinned_dialog_list", true);
14911           d = get_dialog_force(dialog_id, "on_get_dialogs pinned 2");
14912         }
14913         if (d != nullptr && set_dialog_is_pinned(DialogListId(folder_id), d, false)) {
14914           are_pinned_dialogs_saved = true;
14915         }
14916       }
14917     } else {
14918       LOG(INFO) << "Pinned chats are not changed";
14919     }
14920     update_list_last_pinned_dialog_date(*folder_list);
14921 
14922     if (!are_pinned_dialogs_saved && G()->parameters().use_message_db) {
14923       LOG(INFO) << "Save empty pinned chat list in " << folder_id;
14924       G()->td_db()->get_binlog_pmc()->set(PSTRING() << "pinned_dialog_ids" << folder_id.get(), "");
14925     }
14926   }
14927   promise.set_value(Unit());
14928 }
14929 
dump_debug_message_op(const Dialog * d,int priority)14930 void MessagesManager::dump_debug_message_op(const Dialog *d, int priority) {
14931   if (!is_debug_message_op_enabled()) {
14932     return;
14933   }
14934   if (d == nullptr) {
14935     LOG(ERROR) << "Chat not found";
14936     return;
14937   }
14938   static int last_dumped_priority = -1;
14939   if (priority <= last_dumped_priority) {
14940     LOG(ERROR) << "Skip dump " << d->dialog_id;
14941     return;
14942   }
14943   last_dumped_priority = priority;
14944 
14945   for (auto &op : d->debug_message_op) {
14946     switch (op.type) {
14947       case Dialog::MessageOp::Add: {
14948         LOG(ERROR) << "MessageOpAdd at " << op.date << " " << op.message_id << " " << op.content_type << " "
14949                    << op.from_update << " " << op.have_previous << " " << op.have_next << " " << op.source;
14950         break;
14951       }
14952       case Dialog::MessageOp::SetPts: {
14953         LOG(ERROR) << "MessageOpSetPts at " << op.date << " " << op.pts << " " << op.source;
14954         break;
14955       }
14956       case Dialog::MessageOp::Delete: {
14957         LOG(ERROR) << "MessageOpDelete at " << op.date << " " << op.message_id << " " << op.content_type << " "
14958                    << op.from_update << " " << op.have_previous << " " << op.have_next << " " << op.source;
14959         break;
14960       }
14961       case Dialog::MessageOp::DeleteAll: {
14962         LOG(ERROR) << "MessageOpDeleteAll at " << op.date << " " << op.from_update;
14963         break;
14964       }
14965       default:
14966         UNREACHABLE();
14967     }
14968   }
14969 }
14970 
is_message_unload_enabled() const14971 bool MessagesManager::is_message_unload_enabled() const {
14972   return G()->parameters().use_message_db || td_->auth_manager_->is_bot();
14973 }
14974 
can_unload_message(const Dialog * d,const Message * m) const14975 bool MessagesManager::can_unload_message(const Dialog *d, const Message *m) const {
14976   CHECK(d != nullptr);
14977   CHECK(m != nullptr);
14978   CHECK(m->message_id.is_valid());
14979   // don't want to unload messages from opened dialogs
14980   // don't want to unload messages to which there are replies in yet unsent messages
14981   // don't want to unload message with active reply markup
14982   // don't want to unload the newest pinned message
14983   // don't want to unload last edited message, because server can send updateEditChannelMessage again
14984   // can't unload from memory last dialog, last database messages, yet unsent messages, being edited media messages and active live locations
14985   // can't unload messages in dialog with active suffix load query
14986   FullMessageId full_message_id{d->dialog_id, m->message_id};
14987   return !d->is_opened && m->message_id != d->last_message_id && m->message_id != d->last_database_message_id &&
14988          !m->message_id.is_yet_unsent() && active_live_location_full_message_ids_.count(full_message_id) == 0 &&
14989          replied_by_yet_unsent_messages_.count(full_message_id) == 0 && m->edited_content == nullptr &&
14990          d->suffix_load_queries_.empty() && m->message_id != d->reply_markup_message_id &&
14991          m->message_id != d->last_pinned_message_id && m->message_id != d->last_edited_message_id;
14992 }
14993 
unload_message(Dialog * d,MessageId message_id)14994 void MessagesManager::unload_message(Dialog *d, MessageId message_id) {
14995   CHECK(d != nullptr);
14996   CHECK(message_id.is_valid());
14997   bool need_update_dialog_pos = false;
14998   auto m = do_delete_message(d, message_id, false, true, &need_update_dialog_pos, "unload_message");
14999   CHECK(!need_update_dialog_pos);
15000 }
15001 
delete_message(Dialog * d,MessageId message_id,bool is_permanently_deleted,bool * need_update_dialog_pos,const char * source)15002 unique_ptr<MessagesManager::Message> MessagesManager::delete_message(Dialog *d, MessageId message_id,
15003                                                                      bool is_permanently_deleted,
15004                                                                      bool *need_update_dialog_pos, const char *source) {
15005   return do_delete_message(d, message_id, is_permanently_deleted, false, need_update_dialog_pos, source);
15006 }
15007 
add_random_id_to_message_id_correspondence(Dialog * d,int64 random_id,MessageId message_id)15008 void MessagesManager::add_random_id_to_message_id_correspondence(Dialog *d, int64 random_id, MessageId message_id) {
15009   CHECK(d != nullptr);
15010   CHECK(d->dialog_id.get_type() == DialogType::SecretChat);
15011   CHECK(message_id.is_valid());
15012   auto it = d->random_id_to_message_id.find(random_id);
15013   if (it == d->random_id_to_message_id.end() || it->second < message_id) {
15014     LOG(INFO) << "Add correspondence from random_id " << random_id << " to " << message_id << " in " << d->dialog_id;
15015     d->random_id_to_message_id[random_id] = message_id;
15016   }
15017 }
15018 
delete_random_id_to_message_id_correspondence(Dialog * d,int64 random_id,MessageId message_id)15019 void MessagesManager::delete_random_id_to_message_id_correspondence(Dialog *d, int64 random_id, MessageId message_id) {
15020   CHECK(d != nullptr);
15021   CHECK(d->dialog_id.get_type() == DialogType::SecretChat);
15022   CHECK(message_id.is_valid());
15023   auto it = d->random_id_to_message_id.find(random_id);
15024   if (it != d->random_id_to_message_id.end() && it->second == message_id) {
15025     LOG(INFO) << "Delete correspondence from random_id " << random_id << " to " << message_id << " in " << d->dialog_id;
15026     d->random_id_to_message_id.erase(it);
15027   }
15028 }
15029 
add_notification_id_to_message_id_correspondence(Dialog * d,NotificationId notification_id,MessageId message_id)15030 void MessagesManager::add_notification_id_to_message_id_correspondence(Dialog *d, NotificationId notification_id,
15031                                                                        MessageId message_id) {
15032   CHECK(d != nullptr);
15033   CHECK(notification_id.is_valid());
15034   CHECK(message_id.is_valid());
15035   auto it = d->notification_id_to_message_id.find(notification_id);
15036   if (it == d->notification_id_to_message_id.end()) {
15037     VLOG(notifications) << "Add correspondence from " << notification_id << " to " << message_id << " in "
15038                         << d->dialog_id;
15039     d->notification_id_to_message_id.emplace(notification_id, message_id);
15040   } else if (it->second != message_id) {
15041     LOG(ERROR) << "Have duplicated " << notification_id << " in " << d->dialog_id << " in " << message_id << " and "
15042                << it->second;
15043     if (it->second < message_id) {
15044       it->second = message_id;
15045     }
15046   }
15047 }
15048 
delete_notification_id_to_message_id_correspondence(Dialog * d,NotificationId notification_id,MessageId message_id)15049 void MessagesManager::delete_notification_id_to_message_id_correspondence(Dialog *d, NotificationId notification_id,
15050                                                                           MessageId message_id) {
15051   CHECK(d != nullptr);
15052   CHECK(notification_id.is_valid());
15053   CHECK(message_id.is_valid());
15054   auto it = d->notification_id_to_message_id.find(notification_id);
15055   if (it != d->notification_id_to_message_id.end() && it->second == message_id) {
15056     VLOG(notifications) << "Delete correspondence from " << notification_id << " to " << message_id << " in "
15057                         << d->dialog_id;
15058     d->notification_id_to_message_id.erase(it);
15059   } else {
15060     LOG(ERROR) << "Can't find " << notification_id << " in " << d->dialog_id << " with " << message_id;
15061   }
15062 }
15063 
remove_message_notification_id(Dialog * d,Message * m,bool is_permanent,bool force_update,bool ignore_pinned_message_notification_removal)15064 void MessagesManager::remove_message_notification_id(Dialog *d, Message *m, bool is_permanent, bool force_update,
15065                                                      bool ignore_pinned_message_notification_removal) {
15066   CHECK(d != nullptr);
15067   CHECK(m != nullptr);
15068   CHECK(m->message_id.is_valid());
15069   if (!m->notification_id.is_valid()) {
15070     return;
15071   }
15072 
15073   auto from_mentions = is_from_mention_notification_group(d, m);
15074   auto &group_info = get_notification_group_info(d, m);
15075   if (!group_info.group_id.is_valid()) {
15076     return;
15077   }
15078 
15079   bool had_active_notification = is_message_notification_active(d, m);
15080 
15081   auto notification_id = m->notification_id;
15082   VLOG(notifications) << "Remove " << notification_id << " from " << m->message_id << " in " << group_info.group_id
15083                       << '/' << d->dialog_id << " from database, was_active = " << had_active_notification
15084                       << ", is_permanent = " << is_permanent;
15085   delete_notification_id_to_message_id_correspondence(d, notification_id, m->message_id);
15086   m->removed_notification_id = m->notification_id;
15087   m->notification_id = NotificationId();
15088   if (d->pinned_message_notification_message_id == m->message_id && is_permanent &&
15089       !ignore_pinned_message_notification_removal) {
15090     remove_dialog_pinned_message_notification(
15091         d, "remove_message_notification_id");  // must be called after notification_id is removed
15092   }
15093   if (group_info.last_notification_id == notification_id) {
15094     // last notification is deleted, need to find new last notification
15095     fix_dialog_last_notification_id(d, from_mentions, m->message_id);
15096   }
15097 
15098   if (is_permanent) {
15099     if (had_active_notification) {
15100       send_closure_later(G()->notification_manager(), &NotificationManager::remove_notification, group_info.group_id,
15101                          notification_id, is_permanent, force_update, Promise<Unit>(),
15102                          "remove_message_notification_id");
15103     }
15104 
15105     // on_message_changed will be called by the caller
15106     // don't need to call there to not save twice/or to save just deleted message
15107   } else {
15108     on_message_changed(d, m, false, "remove_message_notification_id");
15109   }
15110 }
15111 
remove_new_secret_chat_notification(Dialog * d,bool is_permanent)15112 void MessagesManager::remove_new_secret_chat_notification(Dialog *d, bool is_permanent) {
15113   CHECK(d != nullptr);
15114   auto notification_id = d->new_secret_chat_notification_id;
15115   CHECK(notification_id.is_valid());
15116   VLOG(notifications) << "Remove " << notification_id << " about new secret " << d->dialog_id << " from "
15117                       << d->message_notification_group.group_id;
15118   d->new_secret_chat_notification_id = NotificationId();
15119   bool is_fixed = set_dialog_last_notification(d->dialog_id, d->message_notification_group, 0, NotificationId(),
15120                                                "remove_new_secret_chat_notification");
15121   CHECK(is_fixed);
15122   if (is_permanent) {
15123     CHECK(d->message_notification_group.group_id.is_valid());
15124     send_closure_later(G()->notification_manager(), &NotificationManager::remove_notification,
15125                        d->message_notification_group.group_id, notification_id, true, true, Promise<Unit>(),
15126                        "remove_new_secret_chat_notification");
15127   }
15128 }
15129 
fix_dialog_last_notification_id(Dialog * d,bool from_mentions,MessageId message_id)15130 void MessagesManager::fix_dialog_last_notification_id(Dialog *d, bool from_mentions, MessageId message_id) {
15131   CHECK(d != nullptr);
15132   CHECK(!message_id.is_scheduled());
15133   MessagesConstIterator it(d, message_id);
15134   auto &group_info = from_mentions ? d->mention_notification_group : d->message_notification_group;
15135   VLOG(notifications) << "Trying to fix last notification identifier in " << group_info.group_id << " from "
15136                       << d->dialog_id << " from " << message_id << "/" << group_info.last_notification_id;
15137   if (*it != nullptr && ((*it)->message_id == message_id || (*it)->have_next)) {
15138     while (*it != nullptr) {
15139       const Message *m = *it;
15140       if (is_from_mention_notification_group(d, m) == from_mentions && m->notification_id.is_valid() &&
15141           is_message_notification_active(d, m) && m->message_id != message_id) {
15142         bool is_fixed = set_dialog_last_notification(d->dialog_id, group_info, m->date, m->notification_id,
15143                                                      "fix_dialog_last_notification_id");
15144         CHECK(is_fixed);
15145         return;
15146       }
15147       --it;
15148     }
15149   }
15150   if (G()->parameters().use_message_db) {
15151     get_message_notifications_from_database(
15152         d->dialog_id, group_info.group_id, group_info.last_notification_id, message_id, 1,
15153         PromiseCreator::lambda(
15154             [actor_id = actor_id(this), dialog_id = d->dialog_id, from_mentions,
15155              prev_last_notification_id = group_info.last_notification_id](Result<vector<Notification>> result) {
15156               send_closure(actor_id, &MessagesManager::do_fix_dialog_last_notification_id, dialog_id, from_mentions,
15157                            prev_last_notification_id, std::move(result));
15158             }));
15159   }
15160 }
15161 
do_fix_dialog_last_notification_id(DialogId dialog_id,bool from_mentions,NotificationId prev_last_notification_id,Result<vector<Notification>> result)15162 void MessagesManager::do_fix_dialog_last_notification_id(DialogId dialog_id, bool from_mentions,
15163                                                          NotificationId prev_last_notification_id,
15164                                                          Result<vector<Notification>> result) {
15165   if (result.is_error()) {
15166     return;
15167   }
15168 
15169   Dialog *d = get_dialog(dialog_id);
15170   CHECK(d != nullptr);
15171   auto &group_info = from_mentions ? d->mention_notification_group : d->message_notification_group;
15172   VLOG(notifications) << "Receive " << result.ok().size() << " message notifications in " << group_info.group_id << '/'
15173                       << dialog_id << " from " << prev_last_notification_id;
15174   if (group_info.last_notification_id != prev_last_notification_id) {
15175     // last_notification_id was changed
15176     return;
15177   }
15178 
15179   auto notifications = result.move_as_ok();
15180   CHECK(notifications.size() <= 1);
15181 
15182   int32 last_notification_date = 0;
15183   NotificationId last_notification_id;
15184   if (!notifications.empty()) {
15185     last_notification_date = notifications[0].date;
15186     last_notification_id = notifications[0].notification_id;
15187   }
15188 
15189   bool is_fixed = set_dialog_last_notification(dialog_id, group_info, last_notification_date, last_notification_id,
15190                                                "do_fix_dialog_last_notification_id");
15191   CHECK(is_fixed);
15192 }
15193 
15194 // DO NOT FORGET TO ADD ALL CHANGES OF THIS FUNCTION AS WELL TO do_delete_all_dialog_messages
do_delete_message(Dialog * d,MessageId message_id,bool is_permanently_deleted,bool only_from_memory,bool * need_update_dialog_pos,const char * source)15195 unique_ptr<MessagesManager::Message> MessagesManager::do_delete_message(Dialog *d, MessageId message_id,
15196                                                                         bool is_permanently_deleted,
15197                                                                         bool only_from_memory,
15198                                                                         bool *need_update_dialog_pos,
15199                                                                         const char *source) {
15200   CHECK(d != nullptr);
15201   if (!message_id.is_valid()) {
15202     if (message_id.is_valid_scheduled()) {
15203       return do_delete_scheduled_message(d, message_id, is_permanently_deleted, source);
15204     }
15205 
15206     LOG(ERROR) << "Trying to delete " << message_id << " in " << d->dialog_id << " from " << source;
15207     return nullptr;
15208   }
15209 
15210   FullMessageId full_message_id(d->dialog_id, message_id);
15211   unique_ptr<Message> *v = treap_find_message(&d->messages, message_id);
15212   if (*v == nullptr) {
15213     LOG(INFO) << message_id << " is not found in " << d->dialog_id << " to be deleted from " << source;
15214     if (only_from_memory) {
15215       return nullptr;
15216     }
15217 
15218     if (get_message_force(d, message_id, "do_delete_message") == nullptr) {
15219       // currently there may be a race between add_message_to_database and get_message_force,
15220       // so delete a message from database just in case
15221       delete_message_from_database(d, message_id, nullptr, is_permanently_deleted);
15222 
15223       if (is_permanently_deleted && d->last_clear_history_message_id == message_id) {
15224         set_dialog_last_clear_history_date(d, 0, MessageId(), "do_delete_message");
15225         *need_update_dialog_pos = true;
15226       }
15227 
15228       /*
15229       can't do this because the message may be never received in the dialog, unread count will became negative
15230       // if last_read_inbox_message_id is not known, we can't be sure whether unread_count should be decreased or not
15231       if (message_id.is_valid() && !message_id.is_yet_unsent() && d->is_last_read_inbox_message_id_inited &&
15232           message_id > d->last_read_inbox_message_id && !td_->auth_manager_->is_bot()) {
15233         int32 server_unread_count = d->server_unread_count;
15234         int32 local_unread_count = d->local_unread_count;
15235         int32 &unread_count = message_id.is_server() ? server_unread_count : local_unread_count;
15236         if (unread_count == 0) {
15237           LOG(ERROR) << "Unread count became negative in " << d->dialog_id << " after deletion of " << message_id
15238                      << ". Last read is " << d->last_read_inbox_message_id;
15239           dump_debug_message_op(d, 3);
15240         } else {
15241           unread_count--;
15242           set_dialog_last_read_inbox_message_id(d, MessageId::min(), server_unread_count, local_unread_count, false,
15243                                                 source);
15244         }
15245       }
15246       */
15247       return nullptr;
15248     }
15249     v = treap_find_message(&d->messages, message_id);
15250     CHECK(*v != nullptr);
15251   }
15252 
15253   const Message *m = v->get();
15254   CHECK(m->message_id == message_id);
15255 
15256   if (only_from_memory && !can_unload_message(d, m)) {
15257     return nullptr;
15258   }
15259 
15260   LOG_CHECK(!d->being_deleted_message_id.is_valid())
15261       << d->being_deleted_message_id << " " << message_id << " " << source;
15262   d->being_deleted_message_id = message_id;
15263 
15264   if (is_debug_message_op_enabled()) {
15265     d->debug_message_op.emplace_back(Dialog::MessageOp::Delete, m->message_id, m->content->get_type(), false,
15266                                      m->have_previous, m->have_next, source);
15267   }
15268 
15269   bool need_get_history = false;
15270   if (!only_from_memory) {
15271     LOG(INFO) << "Deleting " << full_message_id << " with have_previous = " << m->have_previous
15272               << " and have_next = " << m->have_next << " from " << source;
15273 
15274     delete_message_from_database(d, message_id, m, is_permanently_deleted);
15275 
15276     delete_active_live_location(d->dialog_id, m);
15277     remove_message_file_sources(d->dialog_id, m);
15278 
15279     if (message_id == d->last_message_id) {
15280       MessagesConstIterator it(d, message_id);
15281       CHECK(*it == m);
15282       if ((*it)->have_previous) {
15283         --it;
15284         if (*it != nullptr) {
15285           set_dialog_last_message_id(d, (*it)->message_id, "do_delete_message");
15286         } else {
15287           LOG(ERROR) << "Have have_previous is true, but there is no previous for " << full_message_id << " from "
15288                      << source;
15289           dump_debug_message_op(d);
15290           set_dialog_last_message_id(d, MessageId(), "do_delete_message");
15291         }
15292       } else {
15293         need_get_history = true;
15294         set_dialog_last_message_id(d, MessageId(), "do_delete_message");
15295         d->delete_last_message_date = m->date;
15296         d->deleted_last_message_id = message_id;
15297         d->is_last_message_deleted_locally = Slice(source) == Slice(DELETE_MESSAGE_USER_REQUEST_SOURCE);
15298         on_dialog_updated(d->dialog_id, "do delete last message");
15299       }
15300       *need_update_dialog_pos = true;
15301     }
15302 
15303     if (message_id == d->last_database_message_id) {
15304       MessagesConstIterator it(d, message_id);
15305       CHECK(*it == m);
15306       while ((*it)->have_previous) {
15307         --it;
15308         if (*it == nullptr || !(*it)->message_id.is_yet_unsent()) {
15309           break;
15310         }
15311       }
15312 
15313       if (*it != nullptr) {
15314         if (!(*it)->message_id.is_yet_unsent() && (*it)->message_id != d->last_database_message_id) {
15315           if ((*it)->message_id < d->first_database_message_id && d->dialog_id.get_type() == DialogType::Channel) {
15316             // possible if messages was deleted from database, but not from memory after updateChannelTooLong
15317             set_dialog_last_database_message_id(d, MessageId(), "do_delete_message");
15318           } else {
15319             set_dialog_last_database_message_id(d, (*it)->message_id, "do_delete_message");
15320             if (d->last_database_message_id < d->first_database_message_id) {
15321               LOG(ERROR) << "Last database " << d->last_database_message_id << " became less than first database "
15322                          << d->first_database_message_id << " after deletion of " << full_message_id;
15323               set_dialog_first_database_message_id(d, d->last_database_message_id, "do_delete_message 2");
15324             }
15325           }
15326         } else {
15327           need_get_history = true;
15328         }
15329       } else {
15330         LOG(ERROR) << "Have have_previous is true, but there is no previous";
15331         dump_debug_message_op(d);
15332       }
15333     }
15334     if (d->last_database_message_id.is_valid()) {
15335       CHECK(d->first_database_message_id.is_valid());
15336     } else {
15337       set_dialog_first_database_message_id(d, MessageId(), "do_delete_message");
15338     }
15339 
15340     if (message_id == d->suffix_load_first_message_id_) {
15341       MessagesConstIterator it(d, message_id);
15342       CHECK(*it == m);
15343       if ((*it)->have_previous) {
15344         --it;
15345         if (*it != nullptr) {
15346           d->suffix_load_first_message_id_ = (*it)->message_id;
15347         } else {
15348           LOG(ERROR) << "Have have_previous is true, but there is no previous for " << full_message_id << " from "
15349                      << source;
15350           dump_debug_message_op(d);
15351           d->suffix_load_first_message_id_ = MessageId();
15352           d->suffix_load_done_ = false;
15353         }
15354       } else {
15355         d->suffix_load_first_message_id_ = MessageId();
15356         d->suffix_load_done_ = false;
15357       }
15358     }
15359   }
15360   if (only_from_memory && message_id >= d->suffix_load_first_message_id_) {
15361     d->suffix_load_first_message_id_ = MessageId();
15362     d->suffix_load_done_ = false;
15363   }
15364 
15365   if (m->have_previous && (only_from_memory || !m->have_next)) {
15366     MessagesIterator it(d, message_id);
15367     CHECK(*it == m);
15368     --it;
15369     Message *prev_m = *it;
15370     if (prev_m != nullptr) {
15371       prev_m->have_next = false;
15372     } else {
15373       LOG(ERROR) << "Have have_previous is true, but there is no previous for " << full_message_id << " from "
15374                  << source;
15375       dump_debug_message_op(d);
15376     }
15377   }
15378   if ((*v)->have_next && (only_from_memory || !(*v)->have_previous)) {
15379     MessagesIterator it(d, message_id);
15380     CHECK(*it == m);
15381     ++it;
15382     Message *next_m = *it;
15383     if (next_m != nullptr) {
15384       next_m->have_previous = false;
15385     } else {
15386       LOG(ERROR) << "Have have_next is true, but there is no next for " << full_message_id << " from " << source;
15387       dump_debug_message_op(d);
15388     }
15389   }
15390 
15391   auto result = treap_delete_message(v);
15392 
15393   d->being_deleted_message_id = MessageId();
15394 
15395   if (!only_from_memory) {
15396     if (need_get_history && !td_->auth_manager_->is_bot() && have_input_peer(d->dialog_id, AccessRights::Read)) {
15397       send_closure_later(actor_id(this), &MessagesManager::get_history_from_the_end, d->dialog_id, true, false,
15398                          Promise<Unit>());
15399     }
15400 
15401     if (d->reply_markup_message_id == message_id) {
15402       set_dialog_reply_markup(d, MessageId());
15403     }
15404     // if last_read_inbox_message_id is not known, we can't be sure whether unread_count should be decreased or not
15405     if (has_incoming_notification(d->dialog_id, result.get()) && message_id > d->last_read_inbox_message_id &&
15406         d->is_last_read_inbox_message_id_inited && !td_->auth_manager_->is_bot()) {
15407       int32 server_unread_count = d->server_unread_count;
15408       int32 local_unread_count = d->local_unread_count;
15409       int32 &unread_count = message_id.is_server() ? server_unread_count : local_unread_count;
15410       if (unread_count == 0) {
15411         if (need_unread_counter(d->order)) {
15412           LOG(ERROR) << "Unread count became negative in " << d->dialog_id << " after deletion of " << message_id
15413                      << ". Last read is " << d->last_read_inbox_message_id;
15414           dump_debug_message_op(d, 3);
15415         }
15416       } else {
15417         unread_count--;
15418         set_dialog_last_read_inbox_message_id(d, MessageId::min(), server_unread_count, local_unread_count, false,
15419                                               source);
15420       }
15421     }
15422     if (result->contains_unread_mention) {
15423       if (d->unread_mention_count == 0) {
15424         if (is_dialog_inited(d)) {
15425           LOG(ERROR) << "Unread mention count became negative in " << d->dialog_id << " after deletion of "
15426                      << message_id;
15427         }
15428       } else {
15429         set_dialog_unread_mention_count(d, d->unread_mention_count - 1);
15430         send_update_chat_unread_mention_count(d);
15431       }
15432     }
15433 
15434     update_message_count_by_index(d, -1, result.get());
15435     update_reply_count_by_message(d, -1, result.get());
15436   }
15437 
15438   on_message_deleted(d, result.get(), is_permanently_deleted, source);
15439 
15440   return result;
15441 }
15442 
on_message_deleted(Dialog * d,Message * m,bool is_permanently_deleted,const char * source)15443 void MessagesManager::on_message_deleted(Dialog *d, Message *m, bool is_permanently_deleted, const char *source) {
15444   // also called for unloaded messages
15445 
15446   if (m->message_id.is_yet_unsent() && m->top_thread_message_id.is_valid()) {
15447     auto it = d->yet_unsent_thread_message_ids.find(m->top_thread_message_id);
15448     CHECK(it != d->yet_unsent_thread_message_ids.end());
15449     auto is_deleted = it->second.erase(m->message_id) > 0;
15450     CHECK(is_deleted);
15451     if (it->second.empty()) {
15452       d->yet_unsent_thread_message_ids.erase(it);
15453     }
15454   }
15455 
15456   cancel_send_deleted_message(d->dialog_id, m, is_permanently_deleted);
15457 
15458   CHECK(m->message_id.is_valid());
15459   switch (d->dialog_id.get_type()) {
15460     case DialogType::User:
15461     case DialogType::Chat:
15462       if (m->message_id.is_server()) {
15463         message_id_to_dialog_id_.erase(m->message_id);
15464       }
15465       break;
15466     case DialogType::Channel:
15467       // nothing to do
15468       break;
15469     case DialogType::SecretChat:
15470       delete_random_id_to_message_id_correspondence(d, m->random_id, m->message_id);
15471       break;
15472     case DialogType::None:
15473     default:
15474       UNREACHABLE();
15475   }
15476   ttl_unregister_message(d->dialog_id, m, source);
15477   ttl_period_unregister_message(d->dialog_id, m);
15478   delete_bot_command_message_id(d->dialog_id, m->message_id);
15479   unregister_message_content(td_, m->content.get(), {d->dialog_id, m->message_id}, "on_message_deleted");
15480   unregister_message_reply(d, m);
15481   if (m->notification_id.is_valid()) {
15482     delete_notification_id_to_message_id_correspondence(d, m->notification_id, m->message_id);
15483   }
15484 }
15485 
do_delete_scheduled_message(Dialog * d,MessageId message_id,bool is_permanently_deleted,const char * source)15486 unique_ptr<MessagesManager::Message> MessagesManager::do_delete_scheduled_message(Dialog *d, MessageId message_id,
15487                                                                                   bool is_permanently_deleted,
15488                                                                                   const char *source) {
15489   CHECK(d != nullptr);
15490   LOG_CHECK(message_id.is_valid_scheduled()) << d->dialog_id << ' ' << message_id << ' ' << source;
15491 
15492   unique_ptr<Message> *v = treap_find_message(&d->scheduled_messages, message_id);
15493   if (*v == nullptr) {
15494     LOG(INFO) << message_id << " is not found in " << d->dialog_id << " to be deleted from " << source;
15495     auto message = get_message_force(d, message_id, "do_delete_scheduled_message");
15496     if (message == nullptr) {
15497       // currently there may be a race between add_message_to_database and get_message_force,
15498       // so delete a message from database just in case
15499       delete_message_from_database(d, message_id, nullptr, is_permanently_deleted);
15500       return nullptr;
15501     }
15502 
15503     message_id = message->message_id;
15504     v = treap_find_message(&d->scheduled_messages, message_id);
15505     CHECK(*v != nullptr);
15506   }
15507 
15508   const Message *m = v->get();
15509   CHECK(m->message_id == message_id);
15510 
15511   LOG(INFO) << "Deleting " << FullMessageId{d->dialog_id, message_id} << " from " << source;
15512 
15513   delete_message_from_database(d, message_id, m, is_permanently_deleted);
15514 
15515   remove_message_file_sources(d->dialog_id, m);
15516 
15517   auto result = treap_delete_message(v);
15518 
15519   if (message_id.is_scheduled_server()) {
15520     size_t erased_count = d->scheduled_message_date.erase(message_id.get_scheduled_server_message_id());
15521     CHECK(erased_count != 0);
15522   }
15523 
15524   cancel_send_deleted_message(d->dialog_id, result.get(), is_permanently_deleted);
15525 
15526   unregister_message_content(td_, result->content.get(), {d->dialog_id, message_id}, "do_delete_scheduled_message");
15527   unregister_message_reply(d, m);
15528 
15529   return result;
15530 }
15531 
do_delete_all_dialog_messages(Dialog * d,unique_ptr<Message> & message,bool is_permanently_deleted,vector<int64> & deleted_message_ids)15532 void MessagesManager::do_delete_all_dialog_messages(Dialog *d, unique_ptr<Message> &message,
15533                                                     bool is_permanently_deleted, vector<int64> &deleted_message_ids) {
15534   if (message == nullptr) {
15535     return;
15536   }
15537   const Message *m = message.get();
15538   MessageId message_id = m->message_id;
15539 
15540   if (is_debug_message_op_enabled()) {
15541     d->debug_message_op.emplace_back(Dialog::MessageOp::Delete, m->message_id, m->content->get_type(), false,
15542                                      m->have_previous, m->have_next, "delete all messages");
15543   }
15544 
15545   LOG(INFO) << "Delete " << message_id;
15546   deleted_message_ids.push_back(message_id.get());
15547 
15548   do_delete_all_dialog_messages(d, message->right, is_permanently_deleted, deleted_message_ids);
15549   do_delete_all_dialog_messages(d, message->left, is_permanently_deleted, deleted_message_ids);
15550 
15551   delete_active_live_location(d->dialog_id, m);
15552   remove_message_file_sources(d->dialog_id, m);
15553 
15554   on_message_deleted(d, message.get(), is_permanently_deleted, "do_delete_all_dialog_messages");
15555 
15556   message = nullptr;
15557 }
15558 
have_dialog(DialogId dialog_id) const15559 bool MessagesManager::have_dialog(DialogId dialog_id) const {
15560   return dialogs_.count(dialog_id) > 0;
15561 }
15562 
load_dialogs(vector<DialogId> dialog_ids,Promise<vector<DialogId>> && promise)15563 void MessagesManager::load_dialogs(vector<DialogId> dialog_ids, Promise<vector<DialogId>> &&promise) {
15564   LOG(INFO) << "Load chats " << format::as_array(dialog_ids);
15565 
15566   Dependencies dependencies;
15567   for (auto dialog_id : dialog_ids) {
15568     if (dialog_id.is_valid() && !have_dialog(dialog_id)) {
15569       add_dialog_dependencies(dependencies, dialog_id);
15570     }
15571   }
15572   resolve_dependencies_force(td_, dependencies, "load_dialogs");
15573 
15574   td::remove_if(dialog_ids, [this](DialogId dialog_id) { return !have_dialog_info(dialog_id); });
15575 
15576   for (auto dialog_id : dialog_ids) {
15577     force_create_dialog(dialog_id, "load_dialogs");
15578   }
15579 
15580   LOG(INFO) << "Loaded chats " << format::as_array(dialog_ids);
15581   promise.set_value(std::move(dialog_ids));
15582 }
15583 
load_dialog(DialogId dialog_id,int left_tries,Promise<Unit> && promise)15584 bool MessagesManager::load_dialog(DialogId dialog_id, int left_tries, Promise<Unit> &&promise) {
15585   if (!dialog_id.is_valid()) {
15586     promise.set_error(Status::Error(400, "Invalid chat identifier specified"));
15587     return false;
15588   }
15589 
15590   if (!have_dialog_force(dialog_id, "load_dialog")) {  // TODO remove _force
15591     if (G()->parameters().use_message_db) {
15592       //      TODO load dialog from database, DialogLoader
15593       //      send_closure_later(actor_id(this), &MessagesManager::load_dialog_from_database, dialog_id,
15594       //      std::move(promise));
15595       //      return false;
15596     }
15597     if (td_->auth_manager_->is_bot()) {
15598       switch (dialog_id.get_type()) {
15599         case DialogType::User: {
15600           auto user_id = dialog_id.get_user_id();
15601           auto have_user = td_->contacts_manager_->get_user(user_id, left_tries, std::move(promise));
15602           if (!have_user) {
15603             return false;
15604           }
15605           break;
15606         }
15607         case DialogType::Chat: {
15608           auto have_chat = td_->contacts_manager_->get_chat(dialog_id.get_chat_id(), left_tries, std::move(promise));
15609           if (!have_chat) {
15610             return false;
15611           }
15612           break;
15613         }
15614         case DialogType::Channel: {
15615           auto have_channel =
15616               td_->contacts_manager_->get_channel(dialog_id.get_channel_id(), left_tries, std::move(promise));
15617           if (!have_channel) {
15618             return false;
15619           }
15620           break;
15621         }
15622         case DialogType::SecretChat:
15623           promise.set_error(Status::Error(400, "Chat not found"));
15624           return false;
15625         case DialogType::None:
15626         default:
15627           UNREACHABLE();
15628       }
15629       if (!have_input_peer(dialog_id, AccessRights::Read)) {
15630         return false;
15631       }
15632 
15633       add_dialog(dialog_id, "load_dialog");
15634       return true;
15635     }
15636 
15637     promise.set_error(Status::Error(400, "Chat not found"));
15638     return false;
15639   }
15640 
15641   promise.set_value(Unit());
15642   return true;
15643 }
15644 
load_dialog_filter(DialogFilterId dialog_filter_id,bool force,Promise<Unit> && promise)15645 void MessagesManager::load_dialog_filter(DialogFilterId dialog_filter_id, bool force, Promise<Unit> &&promise) {
15646   CHECK(!td_->auth_manager_->is_bot());
15647   if (!dialog_filter_id.is_valid()) {
15648     return promise.set_error(Status::Error(400, "Invalid chat filter identifier specified"));
15649   }
15650 
15651   auto filter = get_dialog_filter(dialog_filter_id);
15652   if (filter == nullptr) {
15653     return promise.set_value(Unit());
15654   }
15655 
15656   load_dialog_filter(filter, force, std::move(promise));
15657 }
15658 
load_dialog_filter(const DialogFilter * filter,bool force,Promise<Unit> && promise)15659 void MessagesManager::load_dialog_filter(const DialogFilter *filter, bool force, Promise<Unit> &&promise) {
15660   CHECK(!td_->auth_manager_->is_bot());
15661   vector<InputDialogId> needed_dialog_ids;
15662   for (auto input_dialog_ids :
15663        {&filter->pinned_dialog_ids, &filter->excluded_dialog_ids, &filter->included_dialog_ids}) {
15664     for (const auto &input_dialog_id : *input_dialog_ids) {
15665       if (!have_dialog(input_dialog_id.get_dialog_id())) {
15666         needed_dialog_ids.push_back(input_dialog_id);
15667       }
15668     }
15669   }
15670 
15671   vector<InputDialogId> input_dialog_ids;
15672   for (const auto &input_dialog_id : needed_dialog_ids) {
15673     auto dialog_id = input_dialog_id.get_dialog_id();
15674     // TODO load dialogs asynchronously
15675     if (!have_dialog_force(dialog_id, "load_dialog_filter")) {
15676       if (dialog_id.get_type() == DialogType::SecretChat) {
15677         if (have_dialog_info_force(dialog_id)) {
15678           force_create_dialog(dialog_id, "load_dialog_filter");
15679         }
15680       } else {
15681         input_dialog_ids.push_back(input_dialog_id);
15682       }
15683     }
15684   }
15685 
15686   if (!input_dialog_ids.empty() && !force) {
15687     const size_t MAX_SLICE_SIZE = 100;  // server side limit
15688     MultiPromiseActorSafe mpas{"GetFilterDialogsOnServerMultiPromiseActor"};
15689     mpas.add_promise(std::move(promise));
15690     mpas.set_ignore_errors(true);
15691     auto lock = mpas.get_promise();
15692 
15693     for (size_t i = 0; i < input_dialog_ids.size(); i += MAX_SLICE_SIZE) {
15694       auto end_i = i + MAX_SLICE_SIZE;
15695       auto end = end_i < input_dialog_ids.size() ? input_dialog_ids.begin() + end_i : input_dialog_ids.end();
15696       td_->create_handler<GetDialogsQuery>(mpas.get_promise())->send({input_dialog_ids.begin() + i, end});
15697     }
15698 
15699     lock.set_value(Unit());
15700     return;
15701   }
15702 
15703   promise.set_value(Unit());
15704 }
15705 
get_recommended_dialog_filters(Promise<td_api::object_ptr<td_api::recommendedChatFilters>> && promise)15706 void MessagesManager::get_recommended_dialog_filters(
15707     Promise<td_api::object_ptr<td_api::recommendedChatFilters>> &&promise) {
15708   CHECK(!td_->auth_manager_->is_bot());
15709   auto query_promise =
15710       PromiseCreator::lambda([actor_id = actor_id(this), promise = std::move(promise)](
15711                                  Result<vector<tl_object_ptr<telegram_api::dialogFilterSuggested>>> result) mutable {
15712         send_closure(actor_id, &MessagesManager::on_get_recommended_dialog_filters, std::move(result),
15713                      std::move(promise));
15714       });
15715   td_->create_handler<GetSuggestedDialogFiltersQuery>(std::move(query_promise))->send();
15716 }
15717 
on_get_recommended_dialog_filters(Result<vector<tl_object_ptr<telegram_api::dialogFilterSuggested>>> result,Promise<td_api::object_ptr<td_api::recommendedChatFilters>> && promise)15718 void MessagesManager::on_get_recommended_dialog_filters(
15719     Result<vector<tl_object_ptr<telegram_api::dialogFilterSuggested>>> result,
15720     Promise<td_api::object_ptr<td_api::recommendedChatFilters>> &&promise) {
15721   if (result.is_error()) {
15722     return promise.set_error(result.move_as_error());
15723   }
15724   CHECK(!td_->auth_manager_->is_bot());
15725   auto suggested_filters = result.move_as_ok();
15726 
15727   MultiPromiseActorSafe mpas{"LoadRecommendedFiltersMultiPromiseActor"};
15728   mpas.add_promise(Promise<Unit>());
15729   auto lock = mpas.get_promise();
15730 
15731   vector<RecommendedDialogFilter> filters;
15732   for (auto &suggested_filter : suggested_filters) {
15733     RecommendedDialogFilter filter;
15734     filter.dialog_filter = DialogFilter::get_dialog_filter(std::move(suggested_filter->filter_), false);
15735     CHECK(filter.dialog_filter != nullptr);
15736     filter.dialog_filter->dialog_filter_id = DialogFilterId();  // just in case
15737     load_dialog_filter(filter.dialog_filter.get(), false, mpas.get_promise());
15738 
15739     filter.description = std::move(suggested_filter->description_);
15740     filters.push_back(std::move(filter));
15741   }
15742 
15743   mpas.add_promise(PromiseCreator::lambda([actor_id = actor_id(this), filters = std::move(filters),
15744                                            promise = std::move(promise)](Result<Unit> &&result) mutable {
15745     send_closure(actor_id, &MessagesManager::on_load_recommended_dialog_filters, std::move(result), std::move(filters),
15746                  std::move(promise));
15747   }));
15748   lock.set_value(Unit());
15749 }
15750 
on_load_recommended_dialog_filters(Result<Unit> && result,vector<RecommendedDialogFilter> && filters,Promise<td_api::object_ptr<td_api::recommendedChatFilters>> && promise)15751 void MessagesManager::on_load_recommended_dialog_filters(
15752     Result<Unit> &&result, vector<RecommendedDialogFilter> &&filters,
15753     Promise<td_api::object_ptr<td_api::recommendedChatFilters>> &&promise) {
15754   TRY_STATUS_PROMISE(promise, G()->close_status());
15755   if (result.is_error()) {
15756     return promise.set_error(result.move_as_error());
15757   }
15758   CHECK(!td_->auth_manager_->is_bot());
15759 
15760   auto chat_filters = transform(filters, [this](const RecommendedDialogFilter &filter) {
15761     return td_api::make_object<td_api::recommendedChatFilter>(get_chat_filter_object(filter.dialog_filter.get()),
15762                                                               filter.description);
15763   });
15764   recommended_dialog_filters_ = std::move(filters);
15765   promise.set_value(td_api::make_object<td_api::recommendedChatFilters>(std::move(chat_filters)));
15766 }
15767 
get_dialog_list_last_date(DialogListId dialog_list_id)15768 Result<DialogDate> MessagesManager::get_dialog_list_last_date(DialogListId dialog_list_id) {
15769   CHECK(!td_->auth_manager_->is_bot());
15770 
15771   auto *list_ptr = get_dialog_list(dialog_list_id);
15772   if (list_ptr == nullptr) {
15773     return Status::Error(400, "Chat list not found");
15774   }
15775   return list_ptr->list_last_dialog_date_;
15776 }
15777 
get_dialogs(DialogListId dialog_list_id,DialogDate offset,int32 limit,bool exact_limit,bool force,Promise<Unit> && promise)15778 vector<DialogId> MessagesManager::get_dialogs(DialogListId dialog_list_id, DialogDate offset, int32 limit,
15779                                               bool exact_limit, bool force, Promise<Unit> &&promise) {
15780   CHECK(!td_->auth_manager_->is_bot());
15781 
15782   auto *list_ptr = get_dialog_list(dialog_list_id);
15783   if (list_ptr == nullptr) {
15784     promise.set_error(Status::Error(400, "Chat list not found"));
15785     return {};
15786   }
15787   auto &list = *list_ptr;
15788 
15789   LOG(INFO) << "Get chats in " << dialog_list_id << " with offset " << offset << " and limit " << limit
15790             << ". last_dialog_date = " << list.list_last_dialog_date_
15791             << ", last_pinned_dialog_date_ = " << list.last_pinned_dialog_date_
15792             << ", are_pinned_dialogs_inited_ = " << list.are_pinned_dialogs_inited_;
15793 
15794   if (limit <= 0) {
15795     promise.set_error(Status::Error(400, "Parameter limit must be positive"));
15796     return {};
15797   }
15798 
15799   vector<DialogId> result;
15800   if (dialog_list_id == DialogListId(FolderId::main()) && sponsored_dialog_id_.is_valid()) {
15801     auto d = get_dialog(sponsored_dialog_id_);
15802     CHECK(d != nullptr);
15803     if (is_dialog_sponsored(d)) {
15804       DialogDate date(get_dialog_private_order(&list, d), d->dialog_id);
15805       if (offset < date) {
15806         result.push_back(sponsored_dialog_id_);
15807         offset = date;
15808         limit--;
15809       }
15810     }
15811   }
15812 
15813   if (!list.are_pinned_dialogs_inited_) {
15814     if (limit == 0 || force) {
15815       promise.set_value(Unit());
15816       return result;
15817     } else {
15818       if (dialog_list_id.is_folder()) {
15819         auto &folder = *get_dialog_folder(dialog_list_id.get_folder_id());
15820         if (folder.last_loaded_database_dialog_date_ == folder.last_database_server_dialog_date_ &&
15821             folder.folder_last_dialog_date_ != MAX_DIALOG_DATE) {
15822           load_dialog_list(list, limit, std::move(promise));
15823           return {};
15824         }
15825       }
15826       reload_pinned_dialogs(dialog_list_id, std::move(promise));
15827       return {};
15828     }
15829   }
15830   if (dialog_list_id.is_filter()) {
15831     auto *filter = get_dialog_filter(dialog_list_id.get_filter_id());
15832     CHECK(filter != nullptr);
15833     vector<InputDialogId> input_dialog_ids;
15834     for (const auto &input_dialog_id : filter->pinned_dialog_ids) {
15835       auto dialog_id = input_dialog_id.get_dialog_id();
15836       if (!have_dialog_force(dialog_id, "get_dialogs")) {
15837         if (dialog_id.get_type() == DialogType::SecretChat) {
15838           if (have_dialog_info_force(dialog_id)) {
15839             force_create_dialog(dialog_id, "get_dialogs");
15840           }
15841         } else {
15842           input_dialog_ids.push_back(input_dialog_id);
15843         }
15844       }
15845     }
15846 
15847     if (!input_dialog_ids.empty()) {
15848       if (limit == 0 || force) {
15849         promise.set_value(Unit());
15850         return result;
15851       } else {
15852         td_->create_handler<GetDialogsQuery>(std::move(promise))->send(std::move(input_dialog_ids));
15853         return {};
15854       }
15855     }
15856   }
15857 
15858   bool need_reload_pinned_dialogs = false;
15859   if (!list.pinned_dialogs_.empty() && offset < list.pinned_dialogs_.back() && limit > 0) {
15860     for (auto &pinned_dialog : list.pinned_dialogs_) {
15861       if (offset < pinned_dialog) {
15862         auto dialog_id = pinned_dialog.get_dialog_id();
15863         auto d = get_dialog_force(dialog_id, "get_dialogs");
15864         if (d == nullptr) {
15865           LOG(ERROR) << "Failed to load pinned " << dialog_id << " from " << dialog_list_id;
15866           if (dialog_id.get_type() != DialogType::SecretChat) {
15867             need_reload_pinned_dialogs = true;
15868           }
15869           continue;
15870         }
15871         if (d->order == DEFAULT_ORDER) {
15872           LOG(INFO) << "Loaded pinned " << dialog_id << " with default order in " << dialog_list_id;
15873           continue;
15874         }
15875         result.push_back(dialog_id);
15876         offset = pinned_dialog;
15877         limit--;
15878         if (limit == 0) {
15879           break;
15880         }
15881       }
15882     }
15883   }
15884   if (need_reload_pinned_dialogs) {
15885     reload_pinned_dialogs(dialog_list_id, Auto());
15886   }
15887   update_list_last_pinned_dialog_date(list);
15888 
15889   vector<const DialogFolder *> folders;
15890   vector<std::set<DialogDate>::const_iterator> folder_iterators;
15891   for (auto folder_id : get_dialog_list_folder_ids(list)) {
15892     folders.push_back(get_dialog_folder(folder_id));
15893     folder_iterators.push_back(folders.back()->ordered_dialogs_.upper_bound(offset));
15894   }
15895   while (limit > 0) {
15896     size_t best_pos = 0;
15897     DialogDate best_dialog_date = MAX_DIALOG_DATE;
15898     for (size_t i = 0; i < folders.size(); i++) {
15899       while (folder_iterators[i] != folders[i]->ordered_dialogs_.end() &&
15900              *folder_iterators[i] <= list.list_last_dialog_date_ &&
15901              (!is_dialog_in_list(get_dialog(folder_iterators[i]->get_dialog_id()), dialog_list_id) ||
15902               get_dialog_pinned_order(&list, folder_iterators[i]->get_dialog_id()) != DEFAULT_ORDER)) {
15903         ++folder_iterators[i];
15904       }
15905       if (folder_iterators[i] != folders[i]->ordered_dialogs_.end() &&
15906           *folder_iterators[i] <= list.list_last_dialog_date_ && *folder_iterators[i] < best_dialog_date) {
15907         best_pos = i;
15908         best_dialog_date = *folder_iterators[i];
15909       }
15910     }
15911     if (best_dialog_date == MAX_DIALOG_DATE || best_dialog_date.get_order() == DEFAULT_ORDER) {
15912       break;
15913     }
15914 
15915     limit--;
15916     result.push_back(folder_iterators[best_pos]->get_dialog_id());
15917     ++folder_iterators[best_pos];
15918   }
15919 
15920   if ((!result.empty() && (!exact_limit || limit == 0)) || force || list.list_last_dialog_date_ == MAX_DIALOG_DATE) {
15921     if (limit > 0 && list.list_last_dialog_date_ != MAX_DIALOG_DATE) {
15922       load_dialog_list(list, limit, Promise<Unit>());
15923     }
15924 
15925     promise.set_value(Unit());
15926     return result;
15927   } else {
15928     if (!result.empty()) {
15929       LOG(INFO) << "Have only " << result.size() << " chats, but " << limit << " chats more are needed";
15930     }
15931     load_dialog_list(list, limit, std::move(promise));
15932     return {};
15933   }
15934 }
15935 
load_dialog_list(DialogList & list,int32 limit,Promise<Unit> && promise)15936 void MessagesManager::load_dialog_list(DialogList &list, int32 limit, Promise<Unit> &&promise) {
15937   CHECK(!td_->auth_manager_->is_bot());
15938   if (limit > MAX_GET_DIALOGS + 2) {
15939     limit = MAX_GET_DIALOGS + 2;
15940   }
15941   bool is_request_sent = false;
15942   for (auto folder_id : get_dialog_list_folder_ids(list)) {
15943     const auto &folder = *get_dialog_folder(folder_id);
15944     if (folder.folder_last_dialog_date_ != MAX_DIALOG_DATE) {
15945       load_folder_dialog_list(folder_id, limit, false);
15946       is_request_sent = true;
15947     }
15948   }
15949   if (is_request_sent) {
15950     LOG(INFO) << "Wait for loading of " << limit << " chats in " << list.dialog_list_id;
15951     list.load_list_queries_.push_back(std::move(promise));
15952   } else {
15953     LOG(ERROR) << "There is nothing to load for " << list.dialog_list_id << " with folders "
15954                << get_dialog_list_folder_ids(list);
15955     promise.set_value(Unit());
15956   }
15957 }
15958 
load_folder_dialog_list(FolderId folder_id,int32 limit,bool only_local)15959 void MessagesManager::load_folder_dialog_list(FolderId folder_id, int32 limit, bool only_local) {
15960   if (G()->close_flag()) {
15961     return;
15962   }
15963 
15964   CHECK(!td_->auth_manager_->is_bot());
15965   auto &folder = *get_dialog_folder(folder_id);
15966   if (folder.folder_last_dialog_date_ == MAX_DIALOG_DATE) {
15967     return;
15968   }
15969 
15970   bool use_database = G()->parameters().use_message_db &&
15971                       folder.last_loaded_database_dialog_date_ < folder.last_database_server_dialog_date_;
15972   if (only_local && !use_database) {
15973     return;
15974   }
15975 
15976   auto &multipromise = folder.load_folder_dialog_list_multipromise_;
15977   if (multipromise.promise_count() != 0) {
15978     // queries have already been sent, just wait for the result
15979     LOG(INFO) << "Skip loading of dialog list in " << folder_id << " with limit " << limit
15980               << ", because it is already being loaded";
15981     if (use_database && folder.load_dialog_list_limit_max_ != 0) {
15982       folder.load_dialog_list_limit_max_ = max(folder.load_dialog_list_limit_max_, limit);
15983     }
15984     return;
15985   }
15986   LOG(INFO) << "Load dialog list in " << folder_id << " with limit " << limit;
15987   multipromise.add_promise(PromiseCreator::lambda([actor_id = actor_id(this), folder_id](Result<Unit> result) {
15988     send_closure_later(actor_id, &MessagesManager::on_load_folder_dialog_list, folder_id, std::move(result));
15989   }));
15990 
15991   bool is_query_sent = false;
15992   if (use_database) {
15993     load_folder_dialog_list_from_database(folder_id, limit, multipromise.get_promise());
15994     is_query_sent = true;
15995   } else {
15996     LOG(INFO) << "Get chats from " << folder.last_server_dialog_date_;
15997     multipromise.add_promise(PromiseCreator::lambda([actor_id = actor_id(this), folder_id](Result<Unit> result) {
15998       if (result.is_ok()) {
15999         send_closure(actor_id, &MessagesManager::recalc_unread_count, DialogListId(folder_id), -1, true);
16000       }
16001     }));
16002     auto lock = multipromise.get_promise();
16003     reload_pinned_dialogs(DialogListId(folder_id), multipromise.get_promise());
16004     if (folder.folder_last_dialog_date_ == folder.last_server_dialog_date_) {
16005       send_closure(
16006           td_->create_net_actor<GetDialogListActor>(multipromise.get_promise()), &GetDialogListActor::send, folder_id,
16007           folder.last_server_dialog_date_.get_date(),
16008           folder.last_server_dialog_date_.get_message_id().get_next_server_message_id().get_server_message_id(),
16009           folder.last_server_dialog_date_.get_dialog_id(), int32{MAX_GET_DIALOGS},
16010           get_sequence_dispatcher_id(DialogId(), MessageContentType::None));
16011       is_query_sent = true;
16012     }
16013     if (folder_id == FolderId::main() && folder.last_server_dialog_date_ == MIN_DIALOG_DATE) {
16014       // do not pass promise to not wait for drafts before showing chat list
16015       td_->create_handler<GetAllDraftsQuery>()->send();
16016     }
16017     lock.set_value(Unit());
16018   }
16019   CHECK(is_query_sent);
16020 }
16021 
on_load_folder_dialog_list(FolderId folder_id,Result<Unit> && result)16022 void MessagesManager::on_load_folder_dialog_list(FolderId folder_id, Result<Unit> &&result) {
16023   if (G()->close_flag()) {
16024     return;
16025   }
16026   CHECK(!td_->auth_manager_->is_bot());
16027 
16028   const auto &folder = *get_dialog_folder(folder_id);
16029   if (result.is_ok()) {
16030     LOG(INFO) << "Successfully loaded chats in " << folder_id;
16031     if (folder.last_server_dialog_date_ == MAX_DIALOG_DATE) {
16032       return;
16033     }
16034 
16035     bool need_new_get_dialog_list = false;
16036     for (const auto &list_it : dialog_lists_) {
16037       auto &list = list_it.second;
16038       if (!list.load_list_queries_.empty() && has_dialogs_from_folder(list, folder)) {
16039         LOG(INFO) << "Need to load more chats in " << folder_id << " for " << list_it.first;
16040         need_new_get_dialog_list = true;
16041       }
16042     }
16043     if (need_new_get_dialog_list) {
16044       load_folder_dialog_list(folder_id, int32{MAX_GET_DIALOGS}, false);
16045     }
16046     return;
16047   }
16048 
16049   LOG(WARNING) << "Failed to load chats in " << folder_id << ": " << result.error();
16050   vector<Promise<Unit>> promises;
16051   for (auto &list_it : dialog_lists_) {
16052     auto &list = list_it.second;
16053     if (!list.load_list_queries_.empty() && has_dialogs_from_folder(list, folder)) {
16054       append(promises, std::move(list.load_list_queries_));
16055       list.load_list_queries_.clear();
16056     }
16057   }
16058 
16059   for (auto &promise : promises) {
16060     promise.set_error(result.error().clone());
16061   }
16062 }
16063 
load_folder_dialog_list_from_database(FolderId folder_id,int32 limit,Promise<Unit> && promise)16064 void MessagesManager::load_folder_dialog_list_from_database(FolderId folder_id, int32 limit, Promise<Unit> &&promise) {
16065   CHECK(!td_->auth_manager_->is_bot());
16066   auto &folder = *get_dialog_folder(folder_id);
16067   LOG(INFO) << "Load " << limit << " chats in " << folder_id << " from database from "
16068             << folder.last_loaded_database_dialog_date_
16069             << ", last database server dialog date = " << folder.last_database_server_dialog_date_;
16070 
16071   CHECK(folder.load_dialog_list_limit_max_ == 0);
16072   folder.load_dialog_list_limit_max_ = limit;
16073   G()->td_db()->get_dialog_db_async()->get_dialogs(
16074       folder_id, folder.last_loaded_database_dialog_date_.get_order(),
16075       folder.last_loaded_database_dialog_date_.get_dialog_id(), limit,
16076       PromiseCreator::lambda([actor_id = actor_id(this), folder_id, limit,
16077                               promise = std::move(promise)](DialogDbGetDialogsResult result) mutable {
16078         send_closure(actor_id, &MessagesManager::on_get_dialogs_from_database, folder_id, limit, std::move(result),
16079                      std::move(promise));
16080       }));
16081 }
16082 
on_get_dialogs_from_database(FolderId folder_id,int32 limit,DialogDbGetDialogsResult && dialogs,Promise<Unit> && promise)16083 void MessagesManager::on_get_dialogs_from_database(FolderId folder_id, int32 limit, DialogDbGetDialogsResult &&dialogs,
16084                                                    Promise<Unit> &&promise) {
16085   TRY_STATUS_PROMISE(promise, G()->close_status());
16086   CHECK(!td_->auth_manager_->is_bot());
16087   auto &folder = *get_dialog_folder(folder_id);
16088   LOG(INFO) << "Receive " << dialogs.dialogs.size() << " from expected " << limit << " chats in " << folder_id
16089             << " in from database with next order " << dialogs.next_order << " and next " << dialogs.next_dialog_id;
16090   int32 new_get_dialogs_limit = 0;
16091   int32 have_more_dialogs_in_database = (limit == static_cast<int32>(dialogs.dialogs.size()));
16092   if (have_more_dialogs_in_database && limit < folder.load_dialog_list_limit_max_) {
16093     new_get_dialogs_limit = folder.load_dialog_list_limit_max_ - limit;
16094   }
16095   folder.load_dialog_list_limit_max_ = 0;
16096 
16097   size_t dialogs_skipped = 0;
16098   for (auto &dialog : dialogs.dialogs) {
16099     Dialog *d = on_load_dialog_from_database(DialogId(), std::move(dialog), "on_get_dialogs_from_database");
16100     if (d == nullptr) {
16101       dialogs_skipped++;
16102       continue;
16103     }
16104     if (d->folder_id != folder_id) {
16105       LOG(WARNING) << "Skip " << d->dialog_id << " received from database, because it is in " << d->folder_id
16106                    << " instead of " << folder_id;
16107       dialogs_skipped++;
16108       continue;
16109     }
16110 
16111     LOG(INFO) << "Loaded from database " << d->dialog_id << " with order " << d->order;
16112   }
16113 
16114   DialogDate max_dialog_date(dialogs.next_order, dialogs.next_dialog_id);
16115   if (!have_more_dialogs_in_database) {
16116     folder.last_loaded_database_dialog_date_ = MAX_DIALOG_DATE;
16117     LOG(INFO) << "Set last loaded database dialog date to " << folder.last_loaded_database_dialog_date_;
16118     folder.last_server_dialog_date_ = max(folder.last_server_dialog_date_, folder.last_database_server_dialog_date_);
16119     LOG(INFO) << "Set last server dialog date to " << folder.last_server_dialog_date_;
16120     update_last_dialog_date(folder_id);
16121   } else if (folder.last_loaded_database_dialog_date_ < max_dialog_date) {
16122     folder.last_loaded_database_dialog_date_ = min(max_dialog_date, folder.last_database_server_dialog_date_);
16123     LOG(INFO) << "Set last loaded database dialog date to " << folder.last_loaded_database_dialog_date_;
16124     folder.last_server_dialog_date_ = max(folder.last_server_dialog_date_, folder.last_loaded_database_dialog_date_);
16125     LOG(INFO) << "Set last server dialog date to " << folder.last_server_dialog_date_;
16126     update_last_dialog_date(folder_id);
16127 
16128     for (const auto &list_it : dialog_lists_) {
16129       auto &list = list_it.second;
16130       if (!list.load_list_queries_.empty() && has_dialogs_from_folder(list, folder) && new_get_dialogs_limit < limit) {
16131         new_get_dialogs_limit = limit;
16132       }
16133     }
16134   } else {
16135     LOG(ERROR) << "Last loaded database dialog date didn't increased, skipped " << dialogs_skipped << " chats out of "
16136                << dialogs.dialogs.size();
16137   }
16138 
16139   if (!(folder.last_loaded_database_dialog_date_ < folder.last_database_server_dialog_date_)) {
16140     // have_more_dialogs_in_database = false;
16141     new_get_dialogs_limit = 0;
16142   }
16143 
16144   if (new_get_dialogs_limit == 0) {
16145     preload_folder_dialog_list_timeout_.add_timeout_in(folder_id.get(), 0.2);
16146     promise.set_value(Unit());
16147   } else {
16148     load_folder_dialog_list_from_database(folder_id, new_get_dialogs_limit, std::move(promise));
16149   }
16150 }
16151 
preload_folder_dialog_list(FolderId folder_id)16152 void MessagesManager::preload_folder_dialog_list(FolderId folder_id) {
16153   if (G()->close_flag()) {
16154     LOG(INFO) << "Skip chat list preload in " << folder_id << " because of closing";
16155     return;
16156   }
16157   CHECK(!td_->auth_manager_->is_bot());
16158 
16159   auto &folder = *get_dialog_folder(folder_id);
16160   CHECK(G()->parameters().use_message_db);
16161   if (folder.load_folder_dialog_list_multipromise_.promise_count() != 0) {
16162     LOG(INFO) << "Skip chat list preload in " << folder_id << ", because there is a pending load chat list request";
16163     return;
16164   }
16165 
16166   if (folder.last_loaded_database_dialog_date_ < folder.last_database_server_dialog_date_) {
16167     // if there are some dialogs in database, preload some of them
16168     load_folder_dialog_list(folder_id, 20, true);
16169   } else if (folder.folder_last_dialog_date_ != MAX_DIALOG_DATE) {
16170     // otherwise load more dialogs from the server
16171     load_folder_dialog_list(folder_id, MAX_GET_DIALOGS, false);
16172   } else {
16173     recalc_unread_count(DialogListId(folder_id), -1, false);
16174   }
16175 }
16176 
get_dialogs_from_list(DialogListId dialog_list_id,int32 limit,Promise<td_api::object_ptr<td_api::chats>> && promise)16177 void MessagesManager::get_dialogs_from_list(DialogListId dialog_list_id, int32 limit,
16178                                             Promise<td_api::object_ptr<td_api::chats>> &&promise) {
16179   CHECK(!td_->auth_manager_->is_bot());
16180 
16181   if (get_dialog_list(dialog_list_id) == nullptr) {
16182     return promise.set_error(Status::Error(400, "Chat list not found"));
16183   }
16184 
16185   if (limit <= 0) {
16186     return promise.set_error(Status::Error(400, "Parameter limit must be positive"));
16187   }
16188 
16189   auto task_id = ++current_get_dialogs_task_id_;
16190   auto &task = get_dialogs_tasks_[task_id];
16191   task.dialog_list_id = dialog_list_id;
16192   task.retry_count = 5;
16193   task.limit = limit;
16194   task.promise = std::move(promise);
16195   get_dialogs_from_list_impl(task_id);
16196 }
16197 
get_dialogs_from_list_impl(int64 task_id)16198 void MessagesManager::get_dialogs_from_list_impl(int64 task_id) {
16199   auto task_it = get_dialogs_tasks_.find(task_id);
16200   CHECK(task_it != get_dialogs_tasks_.end());
16201   auto &task = task_it->second;
16202   auto promise = PromiseCreator::lambda([actor_id = actor_id(this), task_id](Result<Unit> &&result) {
16203     // on_get_dialogs_from_list can delete get_dialogs_tasks_[task_id], so it must be called later
16204     send_closure_later(actor_id, &MessagesManager::on_get_dialogs_from_list, task_id, std::move(result));
16205   });
16206   auto dialog_ids = get_dialogs(task.dialog_list_id, MIN_DIALOG_DATE, task.limit, true, false, std::move(promise));
16207   auto &list = *get_dialog_list(task.dialog_list_id);
16208   auto total_count = get_dialog_total_count(list);
16209   LOG(INFO) << "Receive " << dialog_ids.size() << " chats instead of " << task.limit << " out of " << total_count
16210             << " in " << task.dialog_list_id;
16211   CHECK(dialog_ids.size() <= static_cast<size_t>(total_count));
16212   CHECK(dialog_ids.size() <= static_cast<size_t>(task.limit));
16213   if (dialog_ids.size() == static_cast<size_t>(min(total_count, task.limit)) ||
16214       list.list_last_dialog_date_ == MAX_DIALOG_DATE || task.retry_count == 0) {
16215     auto task_promise = std::move(task.promise);
16216     get_dialogs_tasks_.erase(task_it);
16217     if (!task_promise) {
16218       dialog_ids.clear();
16219     }
16220     return task_promise.set_value(get_chats_object(total_count, dialog_ids));
16221   }
16222   // nor the limit, nor the end of the list were reached; wait for the promise
16223 }
16224 
on_get_dialogs_from_list(int64 task_id,Result<Unit> && result)16225 void MessagesManager::on_get_dialogs_from_list(int64 task_id, Result<Unit> &&result) {
16226   auto task_it = get_dialogs_tasks_.find(task_id);
16227   if (task_it == get_dialogs_tasks_.end()) {
16228     // the task has already been completed
16229     LOG(INFO) << "Chat list load task " << task_id << " has already been completed";
16230     return;
16231   }
16232   auto &task = task_it->second;
16233   if (result.is_error()) {
16234     LOG(INFO) << "Chat list load task " << task_id << " failed with the error " << result.error();
16235     auto task_promise = std::move(task.promise);
16236     get_dialogs_tasks_.erase(task_it);
16237     return task_promise.set_error(result.move_as_error());
16238   }
16239 
16240   auto list_ptr = get_dialog_list(task.dialog_list_id);
16241   CHECK(list_ptr != nullptr);
16242   auto &list = *list_ptr;
16243   if (task.last_dialog_date == list.list_last_dialog_date_) {
16244     // no new chats were loaded
16245     task.retry_count--;
16246   } else {
16247     CHECK(task.last_dialog_date < list.list_last_dialog_date_);
16248     task.last_dialog_date = list.list_last_dialog_date_;
16249     task.retry_count = 5;
16250   }
16251   get_dialogs_from_list_impl(task_id);
16252 }
16253 
get_pinned_dialog_ids(DialogListId dialog_list_id) const16254 vector<DialogId> MessagesManager::get_pinned_dialog_ids(DialogListId dialog_list_id) const {
16255   CHECK(!td_->auth_manager_->is_bot());
16256   if (dialog_list_id.is_filter()) {
16257     const auto *filter = get_dialog_filter(dialog_list_id.get_filter_id());
16258     if (filter == nullptr) {
16259       return {};
16260     }
16261     return transform(filter->pinned_dialog_ids, [](auto &input_dialog) { return input_dialog.get_dialog_id(); });
16262   }
16263 
16264   auto *list = get_dialog_list(dialog_list_id);
16265   if (list == nullptr || !list->are_pinned_dialogs_inited_) {
16266     return {};
16267   }
16268   return transform(list->pinned_dialogs_, [](auto &pinned_dialog) { return pinned_dialog.get_dialog_id(); });
16269 }
16270 
reload_pinned_dialogs(DialogListId dialog_list_id,Promise<Unit> && promise)16271 void MessagesManager::reload_pinned_dialogs(DialogListId dialog_list_id, Promise<Unit> &&promise) {
16272   TRY_STATUS_PROMISE(promise, G()->close_status());
16273   CHECK(!td_->auth_manager_->is_bot());
16274 
16275   if (dialog_list_id.is_folder()) {
16276     send_closure(td_->create_net_actor<GetPinnedDialogsActor>(std::move(promise)), &GetPinnedDialogsActor::send,
16277                  dialog_list_id.get_folder_id(), get_sequence_dispatcher_id(DialogId(), MessageContentType::None));
16278   } else if (dialog_list_id.is_filter()) {
16279     schedule_dialog_filters_reload(0.0);
16280     dialog_filter_reload_queries_.push_back(std::move(promise));
16281   }
16282 }
16283 
get_dialog_filters_cache_time()16284 double MessagesManager::get_dialog_filters_cache_time() {
16285   return DIALOG_FILTERS_CACHE_TIME * 0.0001 * Random::fast(9000, 11000);
16286 }
16287 
schedule_dialog_filters_reload(double timeout)16288 void MessagesManager::schedule_dialog_filters_reload(double timeout) {
16289   if (td_->auth_manager_->is_bot()) {
16290     // just in case
16291     return;
16292   }
16293   if (timeout <= 0) {
16294     timeout = 0.0;
16295     if (dialog_filters_updated_date_ != 0) {
16296       dialog_filters_updated_date_ = 0;
16297       save_dialog_filters();
16298     }
16299   }
16300   LOG(INFO) << "Schedule reload of chat filters in " << timeout;
16301   reload_dialog_filters_timeout_.set_callback(std::move(MessagesManager::on_reload_dialog_filters_timeout));
16302   reload_dialog_filters_timeout_.set_callback_data(static_cast<void *>(this));
16303   reload_dialog_filters_timeout_.set_timeout_in(timeout);
16304 }
16305 
on_reload_dialog_filters_timeout(void * messages_manager_ptr)16306 void MessagesManager::on_reload_dialog_filters_timeout(void *messages_manager_ptr) {
16307   if (G()->close_flag()) {
16308     return;
16309   }
16310   auto messages_manager = static_cast<MessagesManager *>(messages_manager_ptr);
16311   send_closure_later(messages_manager->actor_id(messages_manager), &MessagesManager::reload_dialog_filters);
16312 }
16313 
reload_dialog_filters()16314 void MessagesManager::reload_dialog_filters() {
16315   if (G()->close_flag()) {
16316     return;
16317   }
16318   CHECK(!td_->auth_manager_->is_bot());
16319   if (are_dialog_filters_being_synchronized_ || are_dialog_filters_being_reloaded_) {
16320     need_dialog_filters_reload_ = true;
16321     return;
16322   }
16323   LOG(INFO) << "Reload chat filters from server";
16324   are_dialog_filters_being_reloaded_ = true;
16325   need_dialog_filters_reload_ = false;
16326   auto promise = PromiseCreator::lambda(
16327       [actor_id = actor_id(this)](Result<vector<tl_object_ptr<telegram_api::dialogFilter>>> r_filters) {
16328         send_closure(actor_id, &MessagesManager::on_get_dialog_filters, std::move(r_filters), false);
16329       });
16330   td_->create_handler<GetDialogFiltersQuery>(std::move(promise))->send();
16331 }
16332 
on_get_dialog_filters(Result<vector<tl_object_ptr<telegram_api::dialogFilter>>> r_filters,bool dummy)16333 void MessagesManager::on_get_dialog_filters(Result<vector<tl_object_ptr<telegram_api::dialogFilter>>> r_filters,
16334                                             bool dummy) {
16335   are_dialog_filters_being_reloaded_ = false;
16336   if (G()->close_flag()) {
16337     return;
16338   }
16339   CHECK(!td_->auth_manager_->is_bot());
16340   auto promises = std::move(dialog_filter_reload_queries_);
16341   dialog_filter_reload_queries_.clear();
16342   if (r_filters.is_error()) {
16343     for (auto &promise : promises) {
16344       promise.set_error(r_filters.error().clone());
16345     }
16346     LOG(WARNING) << "Receive error " << r_filters.error() << " for GetDialogFiltersQuery";
16347     need_dialog_filters_reload_ = false;
16348     schedule_dialog_filters_reload(Random::fast(60, 5 * 60));
16349     return;
16350   }
16351 
16352   auto filters = r_filters.move_as_ok();
16353   vector<unique_ptr<DialogFilter>> new_server_dialog_filters;
16354   LOG(INFO) << "Receive " << filters.size() << " chat filters from server";
16355   std::unordered_set<DialogFilterId, DialogFilterIdHash> new_dialog_filter_ids;
16356   for (auto &filter : filters) {
16357     auto dialog_filter = DialogFilter::get_dialog_filter(std::move(filter), true);
16358     if (dialog_filter == nullptr) {
16359       continue;
16360     }
16361     if (!new_dialog_filter_ids.insert(dialog_filter->dialog_filter_id).second) {
16362       LOG(ERROR) << "Receive duplicate " << dialog_filter->dialog_filter_id;
16363       continue;
16364     }
16365 
16366     sort_dialog_filter_input_dialog_ids(dialog_filter.get(), "on_get_dialog_filters 1");
16367     new_server_dialog_filters.push_back(std::move(dialog_filter));
16368   }
16369 
16370   bool is_changed = false;
16371   dialog_filters_updated_date_ = G()->unix_time();
16372   if (server_dialog_filters_ != new_server_dialog_filters) {
16373     LOG(INFO) << "Change server chat filters from " << get_dialog_filter_ids(server_dialog_filters_) << " to "
16374               << get_dialog_filter_ids(new_server_dialog_filters);
16375     std::unordered_map<DialogFilterId, const DialogFilter *, DialogFilterIdHash> old_server_dialog_filters;
16376     for (const auto &filter : server_dialog_filters_) {
16377       old_server_dialog_filters.emplace(filter->dialog_filter_id, filter.get());
16378     }
16379     for (const auto &new_server_filter : new_server_dialog_filters) {
16380       auto dialog_filter_id = new_server_filter->dialog_filter_id;
16381       auto old_filter = get_dialog_filter(dialog_filter_id);
16382       auto it = old_server_dialog_filters.find(dialog_filter_id);
16383       if (it != old_server_dialog_filters.end()) {
16384         auto old_server_filter = it->second;
16385         if (*new_server_filter != *old_server_filter) {
16386           if (old_filter == nullptr) {
16387             // the filter was deleted, don't need to edit it
16388           } else {
16389             if (DialogFilter::are_equivalent(*old_filter, *new_server_filter)) {  // fast path
16390               // the filter was edited from this client, nothing to do
16391             } else {
16392               auto new_filter =
16393                   DialogFilter::merge_dialog_filter_changes(old_filter, old_server_filter, new_server_filter.get());
16394               LOG(INFO) << "Old  local filter: " << *old_filter;
16395               LOG(INFO) << "Old server filter: " << *old_server_filter;
16396               LOG(INFO) << "New server filter: " << *new_server_filter;
16397               LOG(INFO) << "New  local filter: " << *new_filter;
16398               sort_dialog_filter_input_dialog_ids(new_filter.get(), "on_get_dialog_filters 2");
16399               if (*new_filter != *old_filter) {
16400                 is_changed = true;
16401                 edit_dialog_filter(std::move(new_filter), "on_get_dialog_filters");
16402               }
16403             }
16404           }
16405         }
16406         old_server_dialog_filters.erase(it);
16407       } else {
16408         if (old_filter == nullptr) {
16409           // the filter was added from another client
16410           is_changed = true;
16411           add_dialog_filter(make_unique<DialogFilter>(*new_server_filter), false, "on_get_dialog_filters");
16412         } else {
16413           // the filter was added from this client
16414           // after that it could be added from another client, or edited from this client, or edited from another client
16415           // prefer local value, so do nothing
16416           // effectively, ignore edits from other clients, if didn't receive UpdateDialogFilterQuery response
16417         }
16418       }
16419     }
16420     vector<DialogFilterId> left_old_server_dialog_filter_ids;
16421     for (const auto &filter : server_dialog_filters_) {
16422       if (old_server_dialog_filters.count(filter->dialog_filter_id) == 0) {
16423         left_old_server_dialog_filter_ids.push_back(filter->dialog_filter_id);
16424       }
16425     }
16426     LOG(INFO) << "Still existing server chat filters: " << left_old_server_dialog_filter_ids;
16427     for (auto &old_server_filter : old_server_dialog_filters) {
16428       auto dialog_filter_id = old_server_filter.first;
16429       // deleted filter
16430       auto old_filter = get_dialog_filter(dialog_filter_id);
16431       if (old_filter == nullptr) {
16432         // the filter was deleted from this client, nothing to do
16433       } else {
16434         // the filter was deleted from another client
16435         // ignore edits done from the current client and just delete the filter
16436         is_changed = true;
16437         delete_dialog_filter(dialog_filter_id, "on_get_dialog_filters");
16438       }
16439     }
16440     bool is_order_changed = [&] {
16441       vector<DialogFilterId> new_server_dialog_filter_ids = get_dialog_filter_ids(new_server_dialog_filters);
16442       CHECK(new_server_dialog_filter_ids.size() >= left_old_server_dialog_filter_ids.size());
16443       new_server_dialog_filter_ids.resize(left_old_server_dialog_filter_ids.size());
16444       return new_server_dialog_filter_ids != left_old_server_dialog_filter_ids;
16445     }();
16446     if (is_order_changed) {  // if order is changed from this and other clients, prefer order from another client
16447       vector<DialogFilterId> new_dialog_filter_order;
16448       for (const auto &new_server_filter : new_server_dialog_filters) {
16449         auto dialog_filter_id = new_server_filter->dialog_filter_id;
16450         if (get_dialog_filter(dialog_filter_id) != nullptr) {
16451           new_dialog_filter_order.push_back(dialog_filter_id);
16452         }
16453       }
16454       is_changed = true;
16455       set_dialog_filters_order(dialog_filters_, new_dialog_filter_order);
16456     }
16457 
16458     server_dialog_filters_ = std::move(new_server_dialog_filters);
16459   }
16460   if (is_changed || !is_update_chat_filters_sent_) {
16461     send_update_chat_filters();
16462   }
16463   schedule_dialog_filters_reload(get_dialog_filters_cache_time());
16464   save_dialog_filters();
16465 
16466   if (need_synchronize_dialog_filters()) {
16467     synchronize_dialog_filters();
16468   }
16469   for (auto &promise : promises) {
16470     promise.set_value(Unit());
16471   }
16472 }
16473 
need_synchronize_dialog_filters() const16474 bool MessagesManager::need_synchronize_dialog_filters() const {
16475   CHECK(!td_->auth_manager_->is_bot());
16476   size_t server_dialog_filter_count = 0;
16477   vector<DialogFilterId> dialog_filter_ids;
16478   for (const auto &dialog_filter : dialog_filters_) {
16479     if (dialog_filter->is_empty(true)) {
16480       continue;
16481     }
16482 
16483     server_dialog_filter_count++;
16484     auto server_dialog_filter = get_server_dialog_filter(dialog_filter->dialog_filter_id);
16485     if (server_dialog_filter == nullptr || !DialogFilter::are_equivalent(*server_dialog_filter, *dialog_filter)) {
16486       // need update dialog filter on server
16487       return true;
16488     }
16489     dialog_filter_ids.push_back(dialog_filter->dialog_filter_id);
16490   }
16491   if (server_dialog_filter_count != server_dialog_filters_.size()) {
16492     // need delete dialog filter on server
16493     return true;
16494   }
16495   if (dialog_filter_ids != get_dialog_filter_ids(server_dialog_filters_)) {
16496     // need reorder dialog filters on server
16497     return true;
16498   }
16499   return false;
16500 }
16501 
synchronize_dialog_filters()16502 void MessagesManager::synchronize_dialog_filters() {
16503   if (G()->close_flag()) {
16504     return;
16505   }
16506   CHECK(!td_->auth_manager_->is_bot());
16507   if (are_dialog_filters_being_synchronized_ || are_dialog_filters_being_reloaded_) {
16508     return;
16509   }
16510   if (need_dialog_filters_reload_) {
16511     return reload_dialog_filters();
16512   }
16513   if (!need_synchronize_dialog_filters()) {
16514     // reload filters to repair their order if the server added new filter to the beginning of the list
16515     return reload_dialog_filters();
16516   }
16517 
16518   LOG(INFO) << "Synchronize chat filter changes with server having local " << get_dialog_filter_ids(dialog_filters_)
16519             << " and server " << get_dialog_filter_ids(server_dialog_filters_);
16520   for (const auto &server_dialog_filter : server_dialog_filters_) {
16521     if (get_dialog_filter(server_dialog_filter->dialog_filter_id) == nullptr) {
16522       return delete_dialog_filter_on_server(server_dialog_filter->dialog_filter_id);
16523     }
16524   }
16525 
16526   vector<DialogFilterId> dialog_filter_ids;
16527   for (const auto &dialog_filter : dialog_filters_) {
16528     if (dialog_filter->is_empty(true)) {
16529       continue;
16530     }
16531 
16532     auto server_dialog_filter = get_server_dialog_filter(dialog_filter->dialog_filter_id);
16533     if (server_dialog_filter == nullptr || !DialogFilter::are_equivalent(*server_dialog_filter, *dialog_filter)) {
16534       return update_dialog_filter_on_server(make_unique<DialogFilter>(*dialog_filter));
16535     }
16536     dialog_filter_ids.push_back(dialog_filter->dialog_filter_id);
16537   }
16538 
16539   if (dialog_filter_ids != get_dialog_filter_ids(server_dialog_filters_)) {
16540     return reorder_dialog_filters_on_server(std::move(dialog_filter_ids));
16541   }
16542 
16543   UNREACHABLE();
16544 }
16545 
search_public_dialogs(const string & query,Promise<Unit> && promise)16546 vector<DialogId> MessagesManager::search_public_dialogs(const string &query, Promise<Unit> &&promise) {
16547   LOG(INFO) << "Search public chats with query = \"" << query << '"';
16548 
16549   if (utf8_length(query) < MIN_SEARCH_PUBLIC_DIALOG_PREFIX_LEN) {
16550     string username = clean_username(query);
16551     if (username[0] == '@') {
16552       username = username.substr(1);
16553     }
16554 
16555     for (auto &short_username : get_valid_short_usernames()) {
16556       if (2 * username.size() > short_username.size() && begins_with(short_username, username)) {
16557         username = short_username.str();
16558         auto it = resolved_usernames_.find(username);
16559         if (it == resolved_usernames_.end()) {
16560           td_->create_handler<ResolveUsernameQuery>(std::move(promise))->send(username);
16561           return {};
16562         }
16563 
16564         if (it->second.expires_at < Time::now()) {
16565           td_->create_handler<ResolveUsernameQuery>(Promise<>())->send(username);
16566         }
16567 
16568         auto dialog_id = it->second.dialog_id;
16569         force_create_dialog(dialog_id, "public dialogs search");
16570 
16571         auto d = get_dialog(dialog_id);
16572         if (d == nullptr || d->order != DEFAULT_ORDER ||
16573             (dialog_id.get_type() == DialogType::User &&
16574              td_->contacts_manager_->is_user_contact(dialog_id.get_user_id()))) {
16575           continue;
16576         }
16577 
16578         promise.set_value(Unit());
16579         return {dialog_id};
16580       }
16581     }
16582     promise.set_value(Unit());
16583     return {};
16584   }
16585 
16586   auto it = found_public_dialogs_.find(query);
16587   if (it != found_public_dialogs_.end()) {
16588     promise.set_value(Unit());
16589     return it->second;
16590   }
16591 
16592   send_search_public_dialogs_query(query, std::move(promise));
16593   return {};
16594 }
16595 
send_search_public_dialogs_query(const string & query,Promise<Unit> && promise)16596 void MessagesManager::send_search_public_dialogs_query(const string &query, Promise<Unit> &&promise) {
16597   auto &promises = search_public_dialogs_queries_[query];
16598   promises.push_back(std::move(promise));
16599   if (promises.size() != 1) {
16600     // query has already been sent, just wait for the result
16601     return;
16602   }
16603 
16604   td_->create_handler<SearchPublicDialogsQuery>()->send(query);
16605 }
16606 
search_dialogs(const string & query,int32 limit,Promise<Unit> && promise)16607 std::pair<int32, vector<DialogId>> MessagesManager::search_dialogs(const string &query, int32 limit,
16608                                                                    Promise<Unit> &&promise) {
16609   LOG(INFO) << "Search chats with query \"" << query << "\" and limit " << limit;
16610   CHECK(!td_->auth_manager_->is_bot());
16611 
16612   if (limit < 0) {
16613     promise.set_error(Status::Error(400, "Limit must be non-negative"));
16614     return {};
16615   }
16616   if (query.empty()) {
16617     return recently_found_dialogs_.get_dialogs(limit, std::move(promise));
16618   }
16619 
16620   auto result = dialogs_hints_.search(query, limit);
16621   vector<DialogId> dialog_ids;
16622   dialog_ids.reserve(result.second.size());
16623   for (auto key : result.second) {
16624     dialog_ids.push_back(DialogId(-key));
16625   }
16626 
16627   promise.set_value(Unit());
16628   return {narrow_cast<int32>(result.first), std::move(dialog_ids)};
16629 }
16630 
get_recently_opened_dialogs(int32 limit,Promise<Unit> && promise)16631 std::pair<int32, vector<DialogId>> MessagesManager::get_recently_opened_dialogs(int32 limit, Promise<Unit> &&promise) {
16632   CHECK(!td_->auth_manager_->is_bot());
16633   return recently_opened_dialogs_.get_dialogs(limit, std::move(promise));
16634 }
16635 
sort_dialogs_by_order(const vector<DialogId> & dialog_ids,int32 limit) const16636 vector<DialogId> MessagesManager::sort_dialogs_by_order(const vector<DialogId> &dialog_ids, int32 limit) const {
16637   CHECK(!td_->auth_manager_->is_bot());
16638   auto fake_order = static_cast<int64>(dialog_ids.size()) + 1;
16639   auto dialog_dates = transform(dialog_ids, [this, &fake_order](DialogId dialog_id) {
16640     const Dialog *d = get_dialog(dialog_id);
16641     CHECK(d != nullptr);
16642     auto order = get_dialog_base_order(d);
16643     if (is_dialog_inited(d) || order != DEFAULT_ORDER) {
16644       return DialogDate(order, dialog_id);
16645     }
16646     // if the dialog is not inited yet, we need to assume that server knows better and the dialog needs to be returned
16647     return DialogDate(fake_order--, dialog_id);
16648   });
16649   if (static_cast<size_t>(limit) >= dialog_dates.size()) {
16650     std::sort(dialog_dates.begin(), dialog_dates.end());
16651   } else {
16652     std::partial_sort(dialog_dates.begin(), dialog_dates.begin() + limit, dialog_dates.end());
16653     dialog_dates.resize(limit, MAX_DIALOG_DATE);
16654   }
16655   while (!dialog_dates.empty() && dialog_dates.back().get_order() == DEFAULT_ORDER) {
16656     dialog_dates.pop_back();
16657   }
16658   return transform(dialog_dates, [](auto dialog_date) { return dialog_date.get_dialog_id(); });
16659 }
16660 
search_dialogs_on_server(const string & query,int32 limit,Promise<Unit> && promise)16661 vector<DialogId> MessagesManager::search_dialogs_on_server(const string &query, int32 limit, Promise<Unit> &&promise) {
16662   LOG(INFO) << "Search chats on server with query \"" << query << "\" and limit " << limit;
16663 
16664   if (limit < 0) {
16665     promise.set_error(Status::Error(400, "Limit must be non-negative"));
16666     return {};
16667   }
16668   if (limit > MAX_GET_DIALOGS) {
16669     limit = MAX_GET_DIALOGS;
16670   }
16671 
16672   if (query.empty()) {
16673     promise.set_value(Unit());
16674     return {};
16675   }
16676 
16677   auto it = found_on_server_dialogs_.find(query);
16678   if (it != found_on_server_dialogs_.end()) {
16679     promise.set_value(Unit());
16680     return sort_dialogs_by_order(it->second, limit);
16681   }
16682 
16683   send_search_public_dialogs_query(query, std::move(promise));
16684   return {};
16685 }
16686 
drop_common_dialogs_cache(UserId user_id)16687 void MessagesManager::drop_common_dialogs_cache(UserId user_id) {
16688   auto it = found_common_dialogs_.find(user_id);
16689   if (it != found_common_dialogs_.end()) {
16690     it->second.is_outdated = true;
16691   }
16692 }
16693 
get_common_dialogs(UserId user_id,DialogId offset_dialog_id,int32 limit,bool force,Promise<Unit> && promise)16694 std::pair<int32, vector<DialogId>> MessagesManager::get_common_dialogs(UserId user_id, DialogId offset_dialog_id,
16695                                                                        int32 limit, bool force,
16696                                                                        Promise<Unit> &&promise) {
16697   if (!td_->contacts_manager_->have_input_user(user_id)) {
16698     promise.set_error(Status::Error(400, "Have no access to the user"));
16699     return {};
16700   }
16701 
16702   if (user_id == td_->contacts_manager_->get_my_id()) {
16703     promise.set_error(Status::Error(400, "Can't get common chats with self"));
16704     return {};
16705   }
16706   if (limit <= 0) {
16707     promise.set_error(Status::Error(400, "Parameter limit must be positive"));
16708     return {};
16709   }
16710   if (limit > MAX_GET_DIALOGS) {
16711     limit = MAX_GET_DIALOGS;
16712   }
16713 
16714   int64 offset_chat_id = 0;
16715   switch (offset_dialog_id.get_type()) {
16716     case DialogType::Chat:
16717       offset_chat_id = offset_dialog_id.get_chat_id().get();
16718       break;
16719     case DialogType::Channel:
16720       offset_chat_id = offset_dialog_id.get_channel_id().get();
16721       break;
16722     case DialogType::None:
16723       if (offset_dialog_id == DialogId()) {
16724         break;
16725       }
16726     // fallthrough
16727     case DialogType::User:
16728     case DialogType::SecretChat:
16729       promise.set_error(Status::Error(400, "Wrong offset_chat_id"));
16730       return {};
16731     default:
16732       UNREACHABLE();
16733       break;
16734   }
16735 
16736   auto it = found_common_dialogs_.find(user_id);
16737   if (it != found_common_dialogs_.end() && !it->second.dialog_ids.empty()) {
16738     int32 total_count = it->second.total_count;
16739     vector<DialogId> &common_dialog_ids = it->second.dialog_ids;
16740     bool use_cache = (!it->second.is_outdated && it->second.received_date >= Time::now() - 3600) || force ||
16741                      offset_chat_id != 0 || common_dialog_ids.size() >= static_cast<size_t>(MAX_GET_DIALOGS);
16742     // use cache if it is up-to-date, or we required to use it or we can't update it
16743     if (use_cache) {
16744       auto offset_it = common_dialog_ids.begin();
16745       if (offset_dialog_id != DialogId()) {
16746         offset_it = std::find(common_dialog_ids.begin(), common_dialog_ids.end(), offset_dialog_id);
16747         if (offset_it == common_dialog_ids.end()) {
16748           promise.set_error(Status::Error(400, "Wrong offset_chat_id"));
16749           return {};
16750         }
16751         ++offset_it;
16752       }
16753       vector<DialogId> result;
16754       while (result.size() < static_cast<size_t>(limit)) {
16755         if (offset_it == common_dialog_ids.end()) {
16756           break;
16757         }
16758         auto dialog_id = *offset_it++;
16759         if (dialog_id == DialogId()) {  // end of the list
16760           promise.set_value(Unit());
16761           return {total_count, std::move(result)};
16762         }
16763         result.push_back(dialog_id);
16764       }
16765       if (result.size() == static_cast<size_t>(limit) || force) {
16766         promise.set_value(Unit());
16767         return {total_count, std::move(result)};
16768       }
16769     }
16770   }
16771 
16772   td_->create_handler<GetCommonDialogsQuery>(std::move(promise))->send(user_id, offset_chat_id, MAX_GET_DIALOGS);
16773   return {};
16774 }
16775 
on_get_common_dialogs(UserId user_id,int64 offset_chat_id,vector<tl_object_ptr<telegram_api::Chat>> && chats,int32 total_count)16776 void MessagesManager::on_get_common_dialogs(UserId user_id, int64 offset_chat_id,
16777                                             vector<tl_object_ptr<telegram_api::Chat>> &&chats, int32 total_count) {
16778   td_->contacts_manager_->on_update_user_common_chat_count(user_id, total_count);
16779 
16780   auto &common_dialogs = found_common_dialogs_[user_id];
16781   if (common_dialogs.is_outdated && offset_chat_id == 0 &&
16782       common_dialogs.dialog_ids.size() < static_cast<size_t>(MAX_GET_DIALOGS)) {
16783     // drop outdated cache if possible
16784     common_dialogs = CommonDialogs();
16785   }
16786   if (common_dialogs.received_date == 0) {
16787     common_dialogs.received_date = Time::now();
16788   }
16789   common_dialogs.is_outdated = false;
16790   auto &result = common_dialogs.dialog_ids;
16791   if (!result.empty() && result.back() == DialogId()) {
16792     return;
16793   }
16794   bool is_last = chats.empty() && offset_chat_id == 0;
16795   for (auto &chat : chats) {
16796     DialogId dialog_id;
16797     switch (chat->get_id()) {
16798       case telegram_api::chatEmpty::ID: {
16799         auto c = static_cast<const telegram_api::chatEmpty *>(chat.get());
16800         ChatId chat_id(c->id_);
16801         if (!chat_id.is_valid()) {
16802           LOG(ERROR) << "Receive invalid " << chat_id;
16803           continue;
16804         }
16805         dialog_id = DialogId(chat_id);
16806         break;
16807       }
16808       case telegram_api::chat::ID: {
16809         auto c = static_cast<const telegram_api::chat *>(chat.get());
16810         ChatId chat_id(c->id_);
16811         if (!chat_id.is_valid()) {
16812           LOG(ERROR) << "Receive invalid " << chat_id;
16813           continue;
16814         }
16815         dialog_id = DialogId(chat_id);
16816         break;
16817       }
16818       case telegram_api::chatForbidden::ID: {
16819         auto c = static_cast<const telegram_api::chatForbidden *>(chat.get());
16820         ChatId chat_id(c->id_);
16821         if (!chat_id.is_valid()) {
16822           LOG(ERROR) << "Receive invalid " << chat_id;
16823           continue;
16824         }
16825         dialog_id = DialogId(chat_id);
16826         break;
16827       }
16828       case telegram_api::channel::ID: {
16829         auto c = static_cast<const telegram_api::channel *>(chat.get());
16830         ChannelId channel_id(c->id_);
16831         if (!channel_id.is_valid()) {
16832           LOG(ERROR) << "Receive invalid " << channel_id;
16833           continue;
16834         }
16835         dialog_id = DialogId(channel_id);
16836         break;
16837       }
16838       case telegram_api::channelForbidden::ID: {
16839         auto c = static_cast<const telegram_api::channelForbidden *>(chat.get());
16840         ChannelId channel_id(c->id_);
16841         if (!channel_id.is_valid()) {
16842           LOG(ERROR) << "Receive invalid " << channel_id;
16843           continue;
16844         }
16845         dialog_id = DialogId(channel_id);
16846         break;
16847       }
16848       default:
16849         UNREACHABLE();
16850     }
16851     CHECK(dialog_id.is_valid());
16852     td_->contacts_manager_->on_get_chat(std::move(chat), "on_get_common_dialogs");
16853 
16854     if (!td::contains(result, dialog_id)) {
16855       force_create_dialog(dialog_id, "get common dialogs");
16856       result.push_back(dialog_id);
16857     }
16858   }
16859   if (result.size() >= static_cast<size_t>(total_count) || is_last) {
16860     if (result.size() != static_cast<size_t>(total_count)) {
16861       LOG(ERROR) << "Fix total count of common groups with " << user_id << " from " << total_count << " to "
16862                  << result.size();
16863       total_count = narrow_cast<int32>(result.size());
16864       td_->contacts_manager_->on_update_user_common_chat_count(user_id, total_count);
16865     }
16866 
16867     result.emplace_back();
16868   }
16869   common_dialogs.total_count = total_count;
16870 }
16871 
block_message_sender_from_replies(MessageId message_id,bool need_delete_message,bool need_delete_all_messages,bool report_spam,Promise<Unit> && promise)16872 void MessagesManager::block_message_sender_from_replies(MessageId message_id, bool need_delete_message,
16873                                                         bool need_delete_all_messages, bool report_spam,
16874                                                         Promise<Unit> &&promise) {
16875   auto dialog_id = DialogId(ContactsManager::get_replies_bot_user_id());
16876   Dialog *d = get_dialog_force(dialog_id, "block_message_sender_from_replies");
16877   if (d == nullptr) {
16878     return promise.set_error(Status::Error(400, "Chat not found"));
16879   }
16880   if (!have_input_peer(dialog_id, AccessRights::Read)) {
16881     return promise.set_error(Status::Error(400, "Not enough rights"));
16882   }
16883 
16884   auto *m = get_message_force(d, message_id, "block_message_sender_from_replies");
16885   if (m == nullptr) {
16886     return promise.set_error(Status::Error(400, "Message not found"));
16887   }
16888   if (m->is_outgoing || m->message_id.is_scheduled() || !m->message_id.is_server()) {
16889     return promise.set_error(Status::Error(400, "Wrong message specified"));
16890   }
16891 
16892   UserId sender_user_id;
16893   if (m->forward_info != nullptr) {
16894     sender_user_id = m->forward_info->sender_user_id;
16895   }
16896   bool need_update_dialog_pos = false;
16897   vector<int64> deleted_message_ids;
16898   if (need_delete_message) {
16899     auto p = delete_message(d, message_id, true, &need_update_dialog_pos, "block_message_sender_from_replies");
16900     CHECK(p.get() == m);
16901     deleted_message_ids.push_back(p->message_id.get());
16902   }
16903   if (need_delete_all_messages && sender_user_id.is_valid()) {
16904     vector<MessageId> message_ids;
16905     find_messages(d->messages.get(), message_ids, [sender_user_id](const Message *m) {
16906       return !m->is_outgoing && m->forward_info != nullptr && m->forward_info->sender_user_id == sender_user_id;
16907     });
16908 
16909     for (auto user_message_id : message_ids) {
16910       auto p = delete_message(d, user_message_id, true, &need_update_dialog_pos, "block_message_sender_from_replies 2");
16911       deleted_message_ids.push_back(p->message_id.get());
16912     }
16913   }
16914 
16915   if (need_update_dialog_pos) {
16916     send_update_chat_last_message(d, "block_message_sender_from_replies");
16917   }
16918 
16919   send_update_delete_messages(dialog_id, std::move(deleted_message_ids), true, false);
16920 
16921   block_message_sender_from_replies_on_server(message_id, need_delete_message, need_delete_all_messages, report_spam, 0,
16922                                               std::move(promise));
16923 }
16924 
16925 class MessagesManager::BlockMessageSenderFromRepliesOnServerLogEvent {
16926  public:
16927   MessageId message_id_;
16928   bool delete_message_;
16929   bool delete_all_messages_;
16930   bool report_spam_;
16931 
16932   template <class StorerT>
store(StorerT & storer) const16933   void store(StorerT &storer) const {
16934     BEGIN_STORE_FLAGS();
16935     STORE_FLAG(delete_message_);
16936     STORE_FLAG(delete_all_messages_);
16937     STORE_FLAG(report_spam_);
16938     END_STORE_FLAGS();
16939 
16940     td::store(message_id_, storer);
16941   }
16942 
16943   template <class ParserT>
parse(ParserT & parser)16944   void parse(ParserT &parser) {
16945     BEGIN_PARSE_FLAGS();
16946     PARSE_FLAG(delete_message_);
16947     PARSE_FLAG(delete_all_messages_);
16948     PARSE_FLAG(report_spam_);
16949     END_PARSE_FLAGS();
16950 
16951     td::parse(message_id_, parser);
16952   }
16953 };
16954 
save_block_message_sender_from_replies_on_server_log_event(MessageId message_id,bool need_delete_message,bool need_delete_all_messages,bool report_spam)16955 uint64 MessagesManager::save_block_message_sender_from_replies_on_server_log_event(MessageId message_id,
16956                                                                                    bool need_delete_message,
16957                                                                                    bool need_delete_all_messages,
16958                                                                                    bool report_spam) {
16959   BlockMessageSenderFromRepliesOnServerLogEvent log_event{message_id, need_delete_message, need_delete_all_messages,
16960                                                           report_spam};
16961   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::BlockMessageSenderFromRepliesOnServer,
16962                     get_log_event_storer(log_event));
16963 }
16964 
block_message_sender_from_replies_on_server(MessageId message_id,bool need_delete_message,bool need_delete_all_messages,bool report_spam,uint64 log_event_id,Promise<Unit> && promise)16965 void MessagesManager::block_message_sender_from_replies_on_server(MessageId message_id, bool need_delete_message,
16966                                                                   bool need_delete_all_messages, bool report_spam,
16967                                                                   uint64 log_event_id, Promise<Unit> &&promise) {
16968   if (log_event_id == 0) {
16969     log_event_id = save_block_message_sender_from_replies_on_server_log_event(message_id, need_delete_message,
16970                                                                               need_delete_all_messages, report_spam);
16971   }
16972 
16973   td_->create_handler<BlockFromRepliesQuery>(get_erase_log_event_promise(log_event_id, std::move(promise)))
16974       ->send(message_id, need_delete_message, need_delete_all_messages, report_spam);
16975 }
16976 
get_blocked_dialogs(int32 offset,int32 limit,Promise<td_api::object_ptr<td_api::messageSenders>> && promise)16977 void MessagesManager::get_blocked_dialogs(int32 offset, int32 limit,
16978                                           Promise<td_api::object_ptr<td_api::messageSenders>> &&promise) {
16979   if (offset < 0) {
16980     return promise.set_error(Status::Error(400, "Parameter offset must be non-negative"));
16981   }
16982 
16983   if (limit <= 0) {
16984     return promise.set_error(Status::Error(400, "Parameter limit must be positive"));
16985   }
16986 
16987   td_->create_handler<GetBlockedDialogsQuery>(std::move(promise))->send(offset, limit);
16988 }
16989 
on_get_blocked_dialogs(int32 offset,int32 limit,int32 total_count,vector<tl_object_ptr<telegram_api::peerBlocked>> && blocked_peers,Promise<td_api::object_ptr<td_api::messageSenders>> && promise)16990 void MessagesManager::on_get_blocked_dialogs(int32 offset, int32 limit, int32 total_count,
16991                                              vector<tl_object_ptr<telegram_api::peerBlocked>> &&blocked_peers,
16992                                              Promise<td_api::object_ptr<td_api::messageSenders>> &&promise) {
16993   LOG(INFO) << "Receive " << blocked_peers.size() << " blocked chats from offset " << offset << " out of "
16994             << total_count;
16995   auto peers = transform(std::move(blocked_peers), [](tl_object_ptr<telegram_api::peerBlocked> &&blocked_peer) {
16996     return std::move(blocked_peer->peer_id_);
16997   });
16998   auto dialog_ids = get_message_sender_dialog_ids(td_, std::move(peers));
16999   if (!dialog_ids.empty() && offset + dialog_ids.size() > static_cast<size_t>(total_count)) {
17000     LOG(ERROR) << "Fix total count of blocked chats from " << total_count << " to " << offset + dialog_ids.size();
17001     total_count = offset + narrow_cast<int32>(dialog_ids.size());
17002   }
17003 
17004   auto senders = transform(dialog_ids, [td = td_](DialogId dialog_id) {
17005     return get_message_sender_object(td, dialog_id, "on_get_blocked_dialogs");
17006   });
17007   promise.set_value(td_api::make_object<td_api::messageSenders>(total_count, std::move(senders)));
17008 }
17009 
get_message_sender(FullMessageId full_message_id)17010 DialogId MessagesManager::get_message_sender(FullMessageId full_message_id) {
17011   const auto *m = get_message_force(full_message_id, "get_message_sender");
17012   if (m == nullptr) {
17013     return DialogId();
17014   }
17015   return get_message_sender(m);
17016 }
17017 
have_message_force(FullMessageId full_message_id,const char * source)17018 bool MessagesManager::have_message_force(FullMessageId full_message_id, const char *source) {
17019   return get_message_force(full_message_id, source) != nullptr;
17020 }
17021 
have_message_force(Dialog * d,MessageId message_id,const char * source)17022 bool MessagesManager::have_message_force(Dialog *d, MessageId message_id, const char *source) {
17023   return get_message_force(d, message_id, source) != nullptr;
17024 }
17025 
get_message(FullMessageId full_message_id)17026 MessagesManager::Message *MessagesManager::get_message(FullMessageId full_message_id) {
17027   Dialog *d = get_dialog(full_message_id.get_dialog_id());
17028   if (d == nullptr) {
17029     return nullptr;
17030   }
17031 
17032   return get_message(d, full_message_id.get_message_id());
17033 }
17034 
get_message(FullMessageId full_message_id) const17035 const MessagesManager::Message *MessagesManager::get_message(FullMessageId full_message_id) const {
17036   const Dialog *d = get_dialog(full_message_id.get_dialog_id());
17037   if (d == nullptr) {
17038     return nullptr;
17039   }
17040 
17041   return get_message(d, full_message_id.get_message_id());
17042 }
17043 
get_message_force(FullMessageId full_message_id,const char * source)17044 MessagesManager::Message *MessagesManager::get_message_force(FullMessageId full_message_id, const char *source) {
17045   Dialog *d = get_dialog_force(full_message_id.get_dialog_id(), source);
17046   if (d == nullptr) {
17047     return nullptr;
17048   }
17049 
17050   return get_message_force(d, full_message_id.get_message_id(), source);
17051 }
17052 
get_replied_message_id(DialogId dialog_id,const Message * m)17053 FullMessageId MessagesManager::get_replied_message_id(DialogId dialog_id, const Message *m) {
17054   auto full_message_id = get_message_content_replied_message_id(dialog_id, m->content.get());
17055   if (full_message_id.get_message_id().is_valid()) {
17056     CHECK(!m->reply_to_message_id.is_valid());
17057     return full_message_id;
17058   }
17059   if (!m->reply_to_message_id.is_valid()) {
17060     return {};
17061   }
17062   return {m->reply_in_dialog_id.is_valid() ? m->reply_in_dialog_id : dialog_id, m->reply_to_message_id};
17063 }
17064 
get_message_force_from_server(Dialog * d,MessageId message_id,Promise<Unit> && promise,tl_object_ptr<telegram_api::InputMessage> input_message)17065 void MessagesManager::get_message_force_from_server(Dialog *d, MessageId message_id, Promise<Unit> &&promise,
17066                                                     tl_object_ptr<telegram_api::InputMessage> input_message) {
17067   LOG(INFO) << "Get " << message_id << " in " << d->dialog_id << " using " << to_string(input_message);
17068   auto dialog_type = d->dialog_id.get_type();
17069   auto m = get_message_force(d, message_id, "get_message_force_from_server");
17070   if (m == nullptr) {
17071     if (message_id.is_valid() && message_id.is_server()) {
17072       if (d->last_new_message_id != MessageId() && message_id > d->last_new_message_id &&
17073           dialog_type != DialogType::Channel) {
17074         // message will not be added to the dialog anyway
17075         return promise.set_value(Unit());
17076       }
17077 
17078       if (d->deleted_message_ids.count(message_id) == 0 && dialog_type != DialogType::SecretChat) {
17079         return get_message_from_server({d->dialog_id, message_id}, std::move(promise), "get_message_force_from_server",
17080                                        std::move(input_message));
17081       }
17082     } else if (message_id.is_valid_scheduled() && message_id.is_scheduled_server()) {
17083       if (d->deleted_scheduled_server_message_ids.count(message_id.get_scheduled_server_message_id()) == 0 &&
17084           dialog_type != DialogType::SecretChat && input_message == nullptr) {
17085         return get_message_from_server({d->dialog_id, message_id}, std::move(promise), "get_message_force_from_server");
17086       }
17087     }
17088   }
17089 
17090   promise.set_value(Unit());
17091 }
17092 
get_message(FullMessageId full_message_id,Promise<Unit> && promise)17093 void MessagesManager::get_message(FullMessageId full_message_id, Promise<Unit> &&promise) {
17094   Dialog *d = get_dialog_force(full_message_id.get_dialog_id(), "get_message");
17095   if (d == nullptr) {
17096     return promise.set_error(Status::Error(400, "Chat not found"));
17097   }
17098 
17099   get_message_force_from_server(d, full_message_id.get_message_id(), std::move(promise));
17100 }
17101 
get_replied_message(DialogId dialog_id,MessageId message_id,bool force,Promise<Unit> && promise)17102 FullMessageId MessagesManager::get_replied_message(DialogId dialog_id, MessageId message_id, bool force,
17103                                                    Promise<Unit> &&promise) {
17104   LOG(INFO) << "Get replied message to " << message_id << " in " << dialog_id;
17105   Dialog *d = get_dialog_force(dialog_id, "get_replied_message");
17106   if (d == nullptr) {
17107     promise.set_error(Status::Error(400, "Chat not found"));
17108     return FullMessageId();
17109   }
17110 
17111   message_id = get_persistent_message_id(d, message_id);
17112   auto m = get_message_force(d, message_id, "get_replied_message");
17113   if (m == nullptr) {
17114     if (force) {
17115       promise.set_value(Unit());
17116     } else {
17117       get_message_force_from_server(d, message_id, std::move(promise));
17118     }
17119     return FullMessageId();
17120   }
17121 
17122   tl_object_ptr<telegram_api::InputMessage> input_message;
17123   auto replied_message_id = get_replied_message_id(dialog_id, m);
17124   if (replied_message_id.get_dialog_id() != dialog_id) {
17125     dialog_id = replied_message_id.get_dialog_id();
17126     if (!have_dialog_info_force(dialog_id)) {
17127       promise.set_value(Unit());
17128       return {};
17129     }
17130     if (!have_input_peer(dialog_id, AccessRights::Read)) {
17131       promise.set_value(Unit());
17132       return {};
17133     }
17134 
17135     force_create_dialog(dialog_id, "get_replied_message");
17136     d = get_dialog_force(dialog_id, "get_replied_message");
17137     if (d == nullptr) {
17138       promise.set_error(Status::Error(500, "Chat with replied message not found"));
17139       return {};
17140     }
17141   } else if (m->message_id.is_valid() && m->message_id.is_server()) {
17142     input_message = make_tl_object<telegram_api::inputMessageReplyTo>(m->message_id.get_server_message_id().get());
17143   }
17144   get_message_force_from_server(d, replied_message_id.get_message_id(), std::move(promise), std::move(input_message));
17145 
17146   return replied_message_id;
17147 }
17148 
get_top_thread_full_message_id(DialogId dialog_id,const Message * m) const17149 Result<FullMessageId> MessagesManager::get_top_thread_full_message_id(DialogId dialog_id, const Message *m) const {
17150   CHECK(m != nullptr);
17151   if (m->message_id.is_scheduled()) {
17152     return Status::Error(400, "Message is scheduled");
17153   }
17154   if (dialog_id.get_type() != DialogType::Channel) {
17155     return Status::Error(400, "Chat can't have message threads");
17156   }
17157   if (!m->reply_info.is_empty() && m->reply_info.is_comment) {
17158     if (!is_visible_message_reply_info(dialog_id, m)) {
17159       return Status::Error(400, "Message has no comments");
17160     }
17161     if (m->message_id.is_yet_unsent()) {
17162       return Status::Error(400, "Message is not sent yet");
17163     }
17164     return FullMessageId{DialogId(m->reply_info.channel_id), m->linked_top_thread_message_id};
17165   } else {
17166     if (!m->top_thread_message_id.is_valid()) {
17167       return Status::Error(400, "Message has no thread");
17168     }
17169     if (!m->message_id.is_server()) {
17170       return Status::Error(400, "Message thread is unavailable for the message");
17171     }
17172     if (m->top_thread_message_id != m->message_id &&
17173         !td_->contacts_manager_->get_channel_has_linked_channel(dialog_id.get_channel_id())) {
17174       return Status::Error(400, "Root message must be used to get the message thread");
17175     }
17176     return FullMessageId{dialog_id, m->top_thread_message_id};
17177   }
17178 }
17179 
get_message_thread(DialogId dialog_id,MessageId message_id,Promise<MessageThreadInfo> && promise)17180 void MessagesManager::get_message_thread(DialogId dialog_id, MessageId message_id,
17181                                          Promise<MessageThreadInfo> &&promise) {
17182   LOG(INFO) << "Get message thread from " << message_id << " in " << dialog_id;
17183   Dialog *d = get_dialog_force(dialog_id, "get_message_thread");
17184   if (d == nullptr) {
17185     return promise.set_error(Status::Error(400, "Chat not found"));
17186   }
17187   if (!have_input_peer(dialog_id, AccessRights::Read)) {
17188     return promise.set_error(Status::Error(400, "Can't access the chat"));
17189   }
17190   if (dialog_id.get_type() != DialogType::Channel) {
17191     return promise.set_error(Status::Error(400, "Chat is not a supergroup or a channel"));
17192   }
17193   if (message_id.is_scheduled()) {
17194     return promise.set_error(Status::Error(400, "Scheduled messages can't have message threads"));
17195   }
17196 
17197   auto m = get_message_force(d, message_id, "get_message_thread");
17198   if (m == nullptr) {
17199     return promise.set_error(Status::Error(400, "Message not found"));
17200   }
17201 
17202   TRY_RESULT_PROMISE(promise, top_thread_full_message_id, get_top_thread_full_message_id(dialog_id, m));
17203 
17204   auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, message_id,
17205                                                promise = std::move(promise)](Result<MessageThreadInfo> result) mutable {
17206     if (result.is_error()) {
17207       return promise.set_error(result.move_as_error());
17208     }
17209     send_closure(actor_id, &MessagesManager::on_get_discussion_message, dialog_id, message_id, result.move_as_ok(),
17210                  std::move(promise));
17211   });
17212 
17213   td_->create_handler<GetDiscussionMessageQuery>(std::move(query_promise))
17214       ->send(dialog_id, message_id, top_thread_full_message_id.get_dialog_id(),
17215              top_thread_full_message_id.get_message_id());
17216 }
17217 
process_discussion_message(telegram_api::object_ptr<telegram_api::messages_discussionMessage> && result,DialogId dialog_id,MessageId message_id,DialogId expected_dialog_id,MessageId expected_message_id,Promise<MessageThreadInfo> promise)17218 void MessagesManager::process_discussion_message(
17219     telegram_api::object_ptr<telegram_api::messages_discussionMessage> &&result, DialogId dialog_id,
17220     MessageId message_id, DialogId expected_dialog_id, MessageId expected_message_id,
17221     Promise<MessageThreadInfo> promise) {
17222   LOG(INFO) << "Receive discussion message for " << message_id << " in " << dialog_id << ": " << to_string(result);
17223   td_->contacts_manager_->on_get_users(std::move(result->users_), "process_discussion_message");
17224   td_->contacts_manager_->on_get_chats(std::move(result->chats_), "process_discussion_message");
17225 
17226   for (auto &message : result->messages_) {
17227     auto message_dialog_id = get_message_dialog_id(message);
17228     if (message_dialog_id != expected_dialog_id) {
17229       return promise.set_error(Status::Error(500, "Expected messages in a different chat"));
17230     }
17231   }
17232 
17233   for (auto &message : result->messages_) {
17234     if (need_channel_difference_to_add_message(expected_dialog_id, message)) {
17235       return run_after_channel_difference(
17236           expected_dialog_id, PromiseCreator::lambda([actor_id = actor_id(this), result = std::move(result), dialog_id,
17237                                                       message_id, expected_dialog_id, expected_message_id,
17238                                                       promise = std::move(promise)](Unit ignored) mutable {
17239             send_closure(actor_id, &MessagesManager::process_discussion_message_impl, std::move(result), dialog_id,
17240                          message_id, expected_dialog_id, expected_message_id, std::move(promise));
17241           }));
17242     }
17243   }
17244 
17245   process_discussion_message_impl(std::move(result), dialog_id, message_id, expected_dialog_id, expected_message_id,
17246                                   std::move(promise));
17247 }
17248 
process_discussion_message_impl(telegram_api::object_ptr<telegram_api::messages_discussionMessage> && result,DialogId dialog_id,MessageId message_id,DialogId expected_dialog_id,MessageId expected_message_id,Promise<MessageThreadInfo> promise)17249 void MessagesManager::process_discussion_message_impl(
17250     telegram_api::object_ptr<telegram_api::messages_discussionMessage> &&result, DialogId dialog_id,
17251     MessageId message_id, DialogId expected_dialog_id, MessageId expected_message_id,
17252     Promise<MessageThreadInfo> promise) {
17253   TRY_STATUS_PROMISE(promise, G()->close_status());
17254 
17255   MessageId max_message_id;
17256   MessageId last_read_inbox_message_id;
17257   MessageId last_read_outbox_message_id;
17258   if ((result->flags_ & telegram_api::messages_discussionMessage::MAX_ID_MASK) != 0) {
17259     max_message_id = MessageId(ServerMessageId(result->max_id_));
17260   }
17261   if ((result->flags_ & telegram_api::messages_discussionMessage::READ_INBOX_MAX_ID_MASK) != 0) {
17262     last_read_inbox_message_id = MessageId(ServerMessageId(result->read_inbox_max_id_));
17263   }
17264   if ((result->flags_ & telegram_api::messages_discussionMessage::READ_OUTBOX_MAX_ID_MASK) != 0) {
17265     last_read_outbox_message_id = MessageId(ServerMessageId(result->read_outbox_max_id_));
17266   }
17267 
17268   MessageThreadInfo message_thread_info;
17269   message_thread_info.dialog_id = expected_dialog_id;
17270   message_thread_info.unread_message_count = max(0, result->unread_count_);
17271   MessageId top_message_id;
17272   for (auto &message : result->messages_) {
17273     auto full_message_id =
17274         on_get_message(std::move(message), false, true, false, false, false, "process_discussion_message_impl");
17275     if (full_message_id.get_message_id().is_valid()) {
17276       CHECK(full_message_id.get_dialog_id() == expected_dialog_id);
17277       message_thread_info.message_ids.push_back(full_message_id.get_message_id());
17278       if (full_message_id.get_message_id() == expected_message_id) {
17279         top_message_id = expected_message_id;
17280       }
17281     }
17282   }
17283   if (!message_thread_info.message_ids.empty() && !top_message_id.is_valid()) {
17284     top_message_id = message_thread_info.message_ids.back();
17285   }
17286   if (top_message_id.is_valid()) {
17287     on_update_read_message_comments(expected_dialog_id, top_message_id, max_message_id, last_read_inbox_message_id,
17288                                     last_read_outbox_message_id);
17289   }
17290   if (expected_dialog_id != dialog_id) {
17291     on_update_read_message_comments(dialog_id, message_id, max_message_id, last_read_inbox_message_id,
17292                                     last_read_outbox_message_id);
17293   }
17294   promise.set_value(std::move(message_thread_info));
17295 }
17296 
on_get_discussion_message(DialogId dialog_id,MessageId message_id,MessageThreadInfo && message_thread_info,Promise<MessageThreadInfo> && promise)17297 void MessagesManager::on_get_discussion_message(DialogId dialog_id, MessageId message_id,
17298                                                 MessageThreadInfo &&message_thread_info,
17299                                                 Promise<MessageThreadInfo> &&promise) {
17300   TRY_STATUS_PROMISE(promise, G()->close_status());
17301 
17302   Dialog *d = get_dialog_force(dialog_id, "on_get_discussion_message");
17303   CHECK(d != nullptr);
17304 
17305   auto m = get_message_force(d, message_id, "on_get_discussion_message");
17306   if (m == nullptr) {
17307     return promise.set_error(Status::Error(400, "Message not found"));
17308   }
17309   if (message_thread_info.message_ids.empty()) {
17310     return promise.set_error(Status::Error(400, "Message has no thread"));
17311   }
17312 
17313   DialogId expected_dialog_id;
17314   if (m->reply_info.is_comment) {
17315     if (!is_active_message_reply_info(dialog_id, m->reply_info)) {
17316       return promise.set_error(Status::Error(400, "Message has no comments"));
17317     }
17318     expected_dialog_id = DialogId(m->reply_info.channel_id);
17319   } else {
17320     if (!m->top_thread_message_id.is_valid()) {
17321       return promise.set_error(Status::Error(400, "Message has no thread"));
17322     }
17323     expected_dialog_id = dialog_id;
17324   }
17325 
17326   if (expected_dialog_id != dialog_id && m->reply_info.is_comment &&
17327       m->linked_top_thread_message_id != message_thread_info.message_ids.back()) {
17328     auto linked_d = get_dialog_force(expected_dialog_id, "on_get_discussion_message 2");
17329     CHECK(linked_d != nullptr);
17330     auto linked_message_id = message_thread_info.message_ids.back();
17331     Message *linked_m = get_message_force(linked_d, linked_message_id, "on_get_discussion_message 3");
17332     CHECK(linked_m != nullptr && linked_m->message_id.is_server());
17333     if (linked_m->top_thread_message_id == linked_m->message_id &&
17334         is_active_message_reply_info(expected_dialog_id, linked_m->reply_info)) {
17335       if (m->linked_top_thread_message_id.is_valid()) {
17336         LOG(ERROR) << "Comment message identifier for " << message_id << " in " << dialog_id << " changed from "
17337                    << m->linked_top_thread_message_id << " to " << linked_message_id;
17338       }
17339       m->linked_top_thread_message_id = linked_message_id;
17340       on_dialog_updated(dialog_id, "on_get_discussion_message");
17341     }
17342   }
17343   promise.set_value(std::move(message_thread_info));
17344 }
17345 
get_message_thread_info_object(const MessageThreadInfo & info)17346 td_api::object_ptr<td_api::messageThreadInfo> MessagesManager::get_message_thread_info_object(
17347     const MessageThreadInfo &info) {
17348   if (info.message_ids.empty()) {
17349     return nullptr;
17350   }
17351 
17352   Dialog *d = get_dialog(info.dialog_id);
17353   CHECK(d != nullptr);
17354   td_api::object_ptr<td_api::messageReplyInfo> reply_info;
17355   vector<td_api::object_ptr<td_api::message>> messages;
17356   messages.reserve(info.message_ids.size());
17357   for (auto message_id : info.message_ids) {
17358     const Message *m = get_message_force(d, message_id, "get_message_thread_info_object");
17359     auto message = get_message_object(d->dialog_id, m, "get_message_thread_info_object");
17360     if (message != nullptr) {
17361       if (message->interaction_info_ != nullptr && message->interaction_info_->reply_info_ != nullptr) {
17362         reply_info = m->reply_info.get_message_reply_info_object(td_->contacts_manager_.get(), this);
17363         CHECK(reply_info != nullptr);
17364       }
17365       messages.push_back(std::move(message));
17366     }
17367   }
17368   if (reply_info == nullptr) {
17369     return nullptr;
17370   }
17371 
17372   MessageId top_thread_message_id;
17373   td_api::object_ptr<td_api::draftMessage> draft_message;
17374   if (!info.message_ids.empty()) {
17375     top_thread_message_id = info.message_ids.back();
17376     if (can_send_message(d->dialog_id).is_ok()) {
17377       const Message *m = get_message_force(d, top_thread_message_id, "get_message_thread_info_object 2");
17378       if (m != nullptr && !m->reply_info.is_comment && is_active_message_reply_info(d->dialog_id, m->reply_info)) {
17379         draft_message = get_draft_message_object(m->thread_draft_message);
17380       }
17381     }
17382   }
17383   return td_api::make_object<td_api::messageThreadInfo>(d->dialog_id.get(), top_thread_message_id.get(),
17384                                                         std::move(reply_info), info.unread_message_count,
17385                                                         std::move(messages), std::move(draft_message));
17386 }
17387 
can_get_message_viewers(FullMessageId full_message_id)17388 Status MessagesManager::can_get_message_viewers(FullMessageId full_message_id) {
17389   auto dialog_id = full_message_id.get_dialog_id();
17390   Dialog *d = get_dialog_force(dialog_id, "get_message_viewers");
17391   if (d == nullptr) {
17392     return Status::Error(400, "Chat not found");
17393   }
17394 
17395   auto m = get_message_force(d, full_message_id.get_message_id(), "get_message_viewers");
17396   if (m == nullptr) {
17397     return Status::Error(400, "Message not found");
17398   }
17399 
17400   return can_get_message_viewers(dialog_id, m);
17401 }
17402 
can_get_message_viewers(DialogId dialog_id,const Message * m) const17403 Status MessagesManager::can_get_message_viewers(DialogId dialog_id, const Message *m) const {
17404   if (td_->auth_manager_->is_bot()) {
17405     return Status::Error(400, "User is bot");
17406   }
17407   CHECK(m != nullptr);
17408   if (!m->is_outgoing) {
17409     return Status::Error(400, "Can't get viewers of incoming messages");
17410   }
17411   if (G()->unix_time() - m->date > G()->shared_config().get_option_integer("chat_read_mark_expire_period", 7 * 86400)) {
17412     return Status::Error(400, "Message is too old");
17413   }
17414 
17415   int32 participant_count = 0;
17416   switch (dialog_id.get_type()) {
17417     case DialogType::User:
17418       return Status::Error(400, "Can't get message viewers in private chats");
17419     case DialogType::Chat:
17420       if (!td_->contacts_manager_->get_chat_is_active(dialog_id.get_chat_id())) {
17421         return Status::Error(400, "Chat is deactivated");
17422       }
17423       participant_count = td_->contacts_manager_->get_chat_participant_count(dialog_id.get_chat_id());
17424       break;
17425     case DialogType::Channel:
17426       if (is_broadcast_channel(dialog_id)) {
17427         return Status::Error(400, "Can't get message viewers in channel chats");
17428       }
17429       participant_count = td_->contacts_manager_->get_channel_participant_count(dialog_id.get_channel_id());
17430       break;
17431     case DialogType::SecretChat:
17432       return Status::Error(400, "Can't get message viewers in secret chats");
17433     case DialogType::None:
17434     default:
17435       UNREACHABLE();
17436       return Status::OK();
17437   }
17438   if (!have_input_peer(dialog_id, AccessRights::Read)) {
17439     return Status::Error(400, "Can't access the chat");
17440   }
17441   if (participant_count == 0) {
17442     return Status::Error(400, "Chat is empty or have unknown number of members");
17443   }
17444   if (participant_count > G()->shared_config().get_option_integer("chat_read_mark_size_threshold", 100)) {
17445     return Status::Error(400, "Chat is too big");
17446   }
17447 
17448   if (m->message_id.is_scheduled()) {
17449     return Status::Error(400, "Scheduled messages can't have viewers");
17450   }
17451   if (m->message_id.is_yet_unsent()) {
17452     return Status::Error(400, "Yet unsent messages can't have viewers");
17453   }
17454   if (m->message_id.is_local()) {
17455     return Status::Error(400, "Local messages can't have viewers");
17456   }
17457   CHECK(m->message_id.is_server());
17458 
17459   if (m->content->get_type() == MessageContentType::Poll &&
17460       get_message_content_poll_is_anonymous(td_, m->content.get())) {
17461   }
17462 
17463   return Status::OK();
17464 }
17465 
get_message_viewers(FullMessageId full_message_id,Promise<td_api::object_ptr<td_api::users>> && promise)17466 void MessagesManager::get_message_viewers(FullMessageId full_message_id,
17467                                           Promise<td_api::object_ptr<td_api::users>> &&promise) {
17468   TRY_STATUS_PROMISE(promise, can_get_message_viewers(full_message_id));
17469 
17470   auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_id = full_message_id.get_dialog_id(),
17471                                                promise = std::move(promise)](Result<vector<UserId>> result) mutable {
17472     if (result.is_error()) {
17473       return promise.set_error(result.move_as_error());
17474     }
17475     send_closure(actor_id, &MessagesManager::on_get_message_viewers, dialog_id, result.move_as_ok(), false,
17476                  std::move(promise));
17477   });
17478 
17479   td_->create_handler<GetMessageReadParticipantsQuery>(std::move(query_promise))
17480       ->send(full_message_id.get_dialog_id(), full_message_id.get_message_id());
17481 }
17482 
on_get_message_viewers(DialogId dialog_id,vector<UserId> user_ids,bool is_recursive,Promise<td_api::object_ptr<td_api::users>> && promise)17483 void MessagesManager::on_get_message_viewers(DialogId dialog_id, vector<UserId> user_ids, bool is_recursive,
17484                                              Promise<td_api::object_ptr<td_api::users>> &&promise) {
17485   if (!is_recursive) {
17486     bool need_participant_list = false;
17487     for (auto user_id : user_ids) {
17488       if (!user_id.is_valid()) {
17489         LOG(ERROR) << "Receive invalid " << user_id << " as viewer of a message in " << dialog_id;
17490         continue;
17491       }
17492       if (!td_->contacts_manager_->have_user_force(user_id)) {
17493         need_participant_list = true;
17494       }
17495     }
17496     if (need_participant_list) {
17497       auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, user_ids = std::move(user_ids),
17498                                                    promise = std::move(promise)](Unit result) mutable {
17499         send_closure(actor_id, &MessagesManager::on_get_message_viewers, dialog_id, std::move(user_ids), true,
17500                      std::move(promise));
17501       });
17502 
17503       switch (dialog_id.get_type()) {
17504         case DialogType::Chat:
17505           return td_->contacts_manager_->reload_chat_full(dialog_id.get_chat_id(), std::move(query_promise));
17506         case DialogType::Channel:
17507           return td_->contacts_manager_->get_channel_participants(
17508               dialog_id.get_channel_id(), td_api::make_object<td_api::supergroupMembersFilterRecent>(), string(), 0,
17509               200, 200, PromiseCreator::lambda([query_promise = std::move(query_promise)](DialogParticipants) mutable {
17510                 query_promise.set_value(Unit());
17511               }));
17512         default:
17513           UNREACHABLE();
17514           return;
17515       }
17516     }
17517   }
17518   promise.set_value(td_->contacts_manager_->get_users_object(-1, user_ids));
17519 }
17520 
get_dialog_info_full(DialogId dialog_id,Promise<Unit> && promise,const char * source)17521 void MessagesManager::get_dialog_info_full(DialogId dialog_id, Promise<Unit> &&promise, const char *source) {
17522   switch (dialog_id.get_type()) {
17523     case DialogType::User:
17524       send_closure_later(td_->contacts_manager_actor_, &ContactsManager::load_user_full, dialog_id.get_user_id(), false,
17525                          std::move(promise), source);
17526       return;
17527     case DialogType::Chat:
17528       send_closure_later(td_->contacts_manager_actor_, &ContactsManager::load_chat_full, dialog_id.get_chat_id(), false,
17529                          std::move(promise), source);
17530       return;
17531     case DialogType::Channel:
17532       send_closure_later(td_->contacts_manager_actor_, &ContactsManager::load_channel_full, dialog_id.get_channel_id(),
17533                          false, std::move(promise), source);
17534       return;
17535     case DialogType::SecretChat:
17536       return promise.set_value(Unit());
17537     case DialogType::None:
17538     default:
17539       UNREACHABLE();
17540       return promise.set_error(Status::Error(500, "Wrong chat type"));
17541   }
17542 }
17543 
reload_dialog_info_full(DialogId dialog_id)17544 void MessagesManager::reload_dialog_info_full(DialogId dialog_id) {
17545   if (G()->close_flag()) {
17546     return;
17547   }
17548 
17549   switch (dialog_id.get_type()) {
17550     case DialogType::User:
17551       send_closure_later(td_->contacts_manager_actor_, &ContactsManager::reload_user_full, dialog_id.get_user_id());
17552       return;
17553     case DialogType::Chat:
17554       send_closure_later(td_->contacts_manager_actor_, &ContactsManager::reload_chat_full, dialog_id.get_chat_id(),
17555                          Promise<Unit>());
17556       return;
17557     case DialogType::Channel:
17558       send_closure_later(td_->contacts_manager_actor_, &ContactsManager::reload_channel_full,
17559                          dialog_id.get_channel_id(), Promise<Unit>(), "reload_dialog_info_full");
17560       return;
17561     case DialogType::SecretChat:
17562       return;
17563     case DialogType::None:
17564     default:
17565       UNREACHABLE();
17566       return;
17567   }
17568 }
17569 
on_dialog_info_full_invalidated(DialogId dialog_id)17570 void MessagesManager::on_dialog_info_full_invalidated(DialogId dialog_id) {
17571   Dialog *d = get_dialog(dialog_id);
17572   if (d != nullptr && d->is_opened) {
17573     reload_dialog_info_full(dialog_id);
17574   }
17575 }
17576 
get_dialog_pinned_message(DialogId dialog_id,Promise<Unit> && promise)17577 MessageId MessagesManager::get_dialog_pinned_message(DialogId dialog_id, Promise<Unit> &&promise) {
17578   Dialog *d = get_dialog_force(dialog_id, "get_dialog_pinned_message");
17579   if (d == nullptr) {
17580     promise.set_error(Status::Error(400, "Chat not found"));
17581     return MessageId();
17582   }
17583 
17584   LOG(INFO) << "Get pinned message in " << dialog_id << " with "
17585             << (d->is_last_pinned_message_id_inited ? "inited" : "unknown") << " pinned " << d->last_pinned_message_id;
17586 
17587   if (!d->is_last_pinned_message_id_inited) {
17588     // must call get_dialog_info_full as expected in fix_new_dialog
17589     get_dialog_info_full(dialog_id, std::move(promise), "get_dialog_pinned_message 1");
17590     return MessageId();
17591   }
17592 
17593   get_dialog_info_full(dialog_id, Auto(), "get_dialog_pinned_message 2");
17594 
17595   if (d->last_pinned_message_id.is_valid()) {
17596     tl_object_ptr<telegram_api::InputMessage> input_message;
17597     if (dialog_id.get_type() == DialogType::Channel) {
17598       input_message = make_tl_object<telegram_api::inputMessagePinned>();
17599     }
17600     get_message_force_from_server(d, d->last_pinned_message_id, std::move(promise), std::move(input_message));
17601   } else {
17602     promise.set_value(Unit());
17603   }
17604 
17605   return d->last_pinned_message_id;
17606 }
17607 
get_callback_query_message(DialogId dialog_id,MessageId message_id,int64 callback_query_id,Promise<Unit> && promise)17608 void MessagesManager::get_callback_query_message(DialogId dialog_id, MessageId message_id, int64 callback_query_id,
17609                                                  Promise<Unit> &&promise) {
17610   Dialog *d = get_dialog_force(dialog_id, "get_callback_query_message");
17611   if (d == nullptr) {
17612     return promise.set_error(Status::Error(400, "Chat not found"));
17613   }
17614   if (!message_id.is_valid() || !message_id.is_server()) {
17615     return promise.set_error(Status::Error(400, "Invalid message identifier specified"));
17616   }
17617 
17618   LOG(INFO) << "Get callback query " << message_id << " in " << dialog_id << " for query " << callback_query_id;
17619 
17620   auto input_message = make_tl_object<telegram_api::inputMessageCallbackQuery>(message_id.get_server_message_id().get(),
17621                                                                                callback_query_id);
17622   get_message_force_from_server(d, message_id, std::move(promise), std::move(input_message));
17623 }
17624 
get_messages(DialogId dialog_id,const vector<MessageId> & message_ids,Promise<Unit> && promise)17625 bool MessagesManager::get_messages(DialogId dialog_id, const vector<MessageId> &message_ids, Promise<Unit> &&promise) {
17626   Dialog *d = get_dialog_force(dialog_id, "get_messages");
17627   if (d == nullptr) {
17628     promise.set_error(Status::Error(400, "Chat not found"));
17629     return false;
17630   }
17631 
17632   bool is_secret = dialog_id.get_type() == DialogType::SecretChat;
17633   vector<FullMessageId> missed_message_ids;
17634   for (auto message_id : message_ids) {
17635     if (!message_id.is_valid() && !message_id.is_valid_scheduled()) {
17636       promise.set_error(Status::Error(400, "Invalid message identifier"));
17637       return false;
17638     }
17639 
17640     auto *m = get_message_force(d, message_id, "get_messages");
17641     if (m == nullptr && message_id.is_any_server() && !is_secret) {
17642       missed_message_ids.emplace_back(dialog_id, message_id);
17643       continue;
17644     }
17645   }
17646 
17647   if (!missed_message_ids.empty()) {
17648     get_messages_from_server(std::move(missed_message_ids), std::move(promise), "get_messages");
17649     return false;
17650   }
17651 
17652   promise.set_value(Unit());
17653   return true;
17654 }
17655 
get_message_from_server(FullMessageId full_message_id,Promise<Unit> && promise,const char * source,tl_object_ptr<telegram_api::InputMessage> input_message)17656 void MessagesManager::get_message_from_server(FullMessageId full_message_id, Promise<Unit> &&promise,
17657                                               const char *source,
17658                                               tl_object_ptr<telegram_api::InputMessage> input_message) {
17659   get_messages_from_server({full_message_id}, std::move(promise), source, std::move(input_message));
17660 }
17661 
get_messages_from_server(vector<FullMessageId> && message_ids,Promise<Unit> && promise,const char * source,tl_object_ptr<telegram_api::InputMessage> input_message)17662 void MessagesManager::get_messages_from_server(vector<FullMessageId> &&message_ids, Promise<Unit> &&promise,
17663                                                const char *source,
17664                                                tl_object_ptr<telegram_api::InputMessage> input_message) {
17665   TRY_STATUS_PROMISE(promise, G()->close_status());
17666 
17667   if (message_ids.empty()) {
17668     LOG(ERROR) << "Empty message_ids from " << source;
17669     return promise.set_error(Status::Error(500, "There are no messages specified to fetch"));
17670   }
17671 
17672   if (input_message != nullptr) {
17673     CHECK(message_ids.size() == 1);
17674   }
17675 
17676   vector<tl_object_ptr<telegram_api::InputMessage>> ordinary_message_ids;
17677   std::unordered_map<ChannelId, vector<tl_object_ptr<telegram_api::InputMessage>>, ChannelIdHash> channel_message_ids;
17678   std::unordered_map<DialogId, vector<int32>, DialogIdHash> scheduled_message_ids;
17679   for (auto &full_message_id : message_ids) {
17680     auto dialog_id = full_message_id.get_dialog_id();
17681     auto message_id = full_message_id.get_message_id();
17682     if (!message_id.is_valid() || !message_id.is_server()) {
17683       if (message_id.is_valid_scheduled() && message_id.is_scheduled_server()) {
17684         scheduled_message_ids[dialog_id].push_back(message_id.get_scheduled_server_message_id().get());
17685       }
17686       continue;
17687     }
17688 
17689     if (input_message == nullptr) {
17690       input_message = make_tl_object<telegram_api::inputMessageID>(message_id.get_server_message_id().get());
17691     }
17692 
17693     switch (dialog_id.get_type()) {
17694       case DialogType::User:
17695       case DialogType::Chat:
17696         ordinary_message_ids.push_back(std::move(input_message));
17697         break;
17698       case DialogType::Channel:
17699         channel_message_ids[dialog_id.get_channel_id()].push_back(std::move(input_message));
17700         break;
17701       case DialogType::SecretChat:
17702         LOG(ERROR) << "Can't get " << full_message_id << " from server from " << source;
17703         break;
17704       case DialogType::None:
17705       default:
17706         UNREACHABLE();
17707         break;
17708     }
17709   }
17710 
17711   MultiPromiseActorSafe mpas{"GetMessagesOnServerMultiPromiseActor"};
17712   mpas.add_promise(std::move(promise));
17713   auto lock = mpas.get_promise();
17714 
17715   if (!ordinary_message_ids.empty()) {
17716     td_->create_handler<GetMessagesQuery>(mpas.get_promise())->send(std::move(ordinary_message_ids));
17717   }
17718 
17719   for (auto &it : scheduled_message_ids) {
17720     auto dialog_id = it.first;
17721     have_dialog_force(dialog_id, "get_messages_from_server");
17722     auto input_peer = get_input_peer(dialog_id, AccessRights::Read);
17723     if (input_peer == nullptr) {
17724       LOG(ERROR) << "Can't find info about " << dialog_id << " to get a message from it from " << source;
17725       mpas.get_promise().set_error(Status::Error(400, "Can't access the chat"));
17726       continue;
17727     }
17728     td_->create_handler<GetScheduledMessagesQuery>(mpas.get_promise())
17729         ->send(dialog_id, std::move(input_peer), std::move(it.second));
17730   }
17731 
17732   for (auto &it : channel_message_ids) {
17733     td_->contacts_manager_->have_channel_force(it.first);
17734     auto input_channel = td_->contacts_manager_->get_input_channel(it.first);
17735     if (input_channel == nullptr) {
17736       LOG(ERROR) << "Can't find info about " << it.first << " to get a message from it from " << source;
17737       mpas.get_promise().set_error(Status::Error(400, "Can't access the chat"));
17738       continue;
17739     }
17740     const auto *d = get_dialog_force(DialogId(it.first));
17741     td_->create_handler<GetChannelMessagesQuery>(mpas.get_promise())
17742         ->send(it.first, std::move(input_channel), std::move(it.second),
17743                d == nullptr ? MessageId() : d->last_new_message_id);
17744   }
17745   lock.set_value(Unit());
17746 }
17747 
is_message_edited_recently(FullMessageId full_message_id,int32 seconds)17748 bool MessagesManager::is_message_edited_recently(FullMessageId full_message_id, int32 seconds) {
17749   if (seconds < 0) {
17750     return false;
17751   }
17752   if (!full_message_id.get_message_id().is_valid()) {
17753     return false;
17754   }
17755 
17756   auto m = get_message_force(full_message_id, "is_message_edited_recently");
17757   if (m == nullptr) {
17758     return true;
17759   }
17760 
17761   return m->edit_date >= G()->unix_time() - seconds;
17762 }
17763 
can_get_media_timestamp_link(DialogId dialog_id,const Message * m)17764 Status MessagesManager::can_get_media_timestamp_link(DialogId dialog_id, const Message *m) {
17765   if (m == nullptr) {
17766     return Status::Error(400, "Message not found");
17767   }
17768 
17769   if (dialog_id.get_type() != DialogType::Channel) {
17770     auto forward_info = m->forward_info.get();
17771     if (!can_message_content_have_media_timestamp(m->content.get()) || forward_info == nullptr ||
17772         forward_info->is_imported || is_forward_info_sender_hidden(forward_info) ||
17773         !forward_info->message_id.is_valid() || !m->forward_info->message_id.is_server() ||
17774         !forward_info->sender_dialog_id.is_valid() ||
17775         forward_info->sender_dialog_id.get_type() != DialogType::Channel) {
17776       return Status::Error(400, "Message links are available only for messages in supergroups and channel chats");
17777     }
17778     return Status::OK();
17779   }
17780 
17781   if (m->message_id.is_yet_unsent()) {
17782     return Status::Error(400, "Message is not sent yet");
17783   }
17784   if (m->message_id.is_scheduled()) {
17785     return Status::Error(400, "Message is scheduled");
17786   }
17787   if (!m->message_id.is_server()) {
17788     return Status::Error(400, "Message is local");
17789   }
17790   return Status::OK();
17791 }
17792 
get_message_link(FullMessageId full_message_id,int32 media_timestamp,bool for_group,bool for_comment)17793 Result<std::pair<string, bool>> MessagesManager::get_message_link(FullMessageId full_message_id, int32 media_timestamp,
17794                                                                   bool for_group, bool for_comment) {
17795   auto dialog_id = full_message_id.get_dialog_id();
17796   auto d = get_dialog_force(dialog_id, "get_message_link");
17797   if (d == nullptr) {
17798     return Status::Error(400, "Chat not found");
17799   }
17800   if (!have_input_peer(dialog_id, AccessRights::Read)) {
17801     return Status::Error(400, "Can't access the chat");
17802   }
17803 
17804   auto *m = get_message_force(d, full_message_id.get_message_id(), "get_message_link");
17805   TRY_STATUS(can_get_media_timestamp_link(dialog_id, m));
17806 
17807   if (media_timestamp <= 0 || !can_message_content_have_media_timestamp(m->content.get())) {
17808     media_timestamp = 0;
17809   }
17810   if (media_timestamp != 0) {
17811     for_group = false;
17812     auto duration = get_message_content_media_duration(m->content.get(), td_);
17813     if (duration != 0 && media_timestamp > duration) {
17814       media_timestamp = 0;
17815     }
17816   }
17817 
17818   auto message_id = m->message_id;
17819   if (dialog_id.get_type() != DialogType::Channel) {
17820     CHECK(m->forward_info != nullptr);
17821     CHECK(m->forward_info->sender_dialog_id.get_type() == DialogType::Channel);
17822 
17823     dialog_id = m->forward_info->sender_dialog_id;
17824     message_id = m->forward_info->message_id;
17825     for_group = false;
17826     for_comment = false;
17827     auto channel_message = get_message({dialog_id, message_id});
17828     if (channel_message != nullptr && channel_message->media_album_id == 0) {
17829       for_group = true;  // default is true
17830     }
17831   } else {
17832     if (m->media_album_id == 0) {
17833       for_group = true;  // default is true
17834     }
17835   }
17836 
17837   if (!m->top_thread_message_id.is_valid() || !m->top_thread_message_id.is_server()) {
17838     for_comment = false;
17839   }
17840   if (d->deleted_message_ids.count(m->top_thread_message_id) != 0) {
17841     for_comment = false;
17842   }
17843   if (for_comment && is_broadcast_channel(dialog_id)) {
17844     for_comment = false;
17845   }
17846 
17847   if (!td_->auth_manager_->is_bot()) {
17848     td_->create_handler<ExportChannelMessageLinkQuery>(Promise<Unit>())
17849         ->send(dialog_id.get_channel_id(), message_id, for_group, true);
17850   }
17851 
17852   SliceBuilder sb;
17853   sb << G()->shared_config().get_option_string("t_me_url", "https://t.me/");
17854 
17855   if (for_comment) {
17856     auto *top_m = get_message_force(d, m->top_thread_message_id, "get_public_message_link");
17857     if (is_discussion_message(dialog_id, top_m) && is_active_message_reply_info(dialog_id, top_m->reply_info)) {
17858       auto linked_dialog_id = top_m->forward_info->from_dialog_id;
17859       auto linked_message_id = top_m->forward_info->from_message_id;
17860       auto linked_d = get_dialog(linked_dialog_id);
17861       CHECK(linked_d != nullptr);
17862       CHECK(linked_dialog_id.get_type() == DialogType::Channel);
17863       auto *linked_m = get_message_force(linked_d, linked_message_id, "get_public_message_link");
17864       auto channel_username = td_->contacts_manager_->get_channel_username(linked_dialog_id.get_channel_id());
17865       if (linked_m != nullptr && is_active_message_reply_info(linked_dialog_id, linked_m->reply_info) &&
17866           linked_message_id.is_server() && have_input_peer(linked_dialog_id, AccessRights::Read) &&
17867           !channel_username.empty()) {
17868         sb << channel_username << '/' << linked_message_id.get_server_message_id().get()
17869            << "?comment=" << message_id.get_server_message_id().get();
17870         if (!for_group) {
17871           sb << "&single";
17872         }
17873         if (media_timestamp > 0) {
17874           sb << "&t=" << media_timestamp;
17875         }
17876         return std::make_pair(sb.as_cslice().str(), true);
17877       }
17878     }
17879   }
17880 
17881   auto dialog_username = td_->contacts_manager_->get_channel_username(dialog_id.get_channel_id());
17882   bool is_public = !dialog_username.empty();
17883   if (m->content->get_type() == MessageContentType::VideoNote && is_broadcast_channel(dialog_id) && is_public) {
17884     return std::make_pair(
17885         PSTRING() << "https://telesco.pe/" << dialog_username << '/' << message_id.get_server_message_id().get(), true);
17886   }
17887 
17888   if (is_public) {
17889     sb << dialog_username;
17890   } else {
17891     sb << "c/" << dialog_id.get_channel_id().get();
17892   }
17893   sb << '/' << message_id.get_server_message_id().get();
17894 
17895   char separator = '?';
17896   if (for_comment) {
17897     sb << separator << "thread=" << m->top_thread_message_id.get_server_message_id().get();
17898     separator = '&';
17899   }
17900   if (!for_group) {
17901     sb << separator << "single";
17902     separator = '&';
17903   }
17904   if (media_timestamp > 0) {
17905     sb << separator << "t=" << media_timestamp;
17906     separator = '&';
17907   }
17908 
17909   return std::make_pair(sb.as_cslice().str(), is_public);
17910 }
17911 
get_message_embedding_code(FullMessageId full_message_id,bool for_group,Promise<Unit> && promise)17912 string MessagesManager::get_message_embedding_code(FullMessageId full_message_id, bool for_group,
17913                                                    Promise<Unit> &&promise) {
17914   auto dialog_id = full_message_id.get_dialog_id();
17915   auto d = get_dialog_force(dialog_id, "get_message_embedding_code");
17916   if (d == nullptr) {
17917     promise.set_error(Status::Error(400, "Chat not found"));
17918     return {};
17919   }
17920   if (!have_input_peer(dialog_id, AccessRights::Read)) {
17921     promise.set_error(Status::Error(400, "Can't access the chat"));
17922     return {};
17923   }
17924   if (dialog_id.get_type() != DialogType::Channel ||
17925       td_->contacts_manager_->get_channel_username(dialog_id.get_channel_id()).empty()) {
17926     promise.set_error(Status::Error(
17927         400, "Message embedding code is available only for messages in public supergroups and channel chats"));
17928     return {};
17929   }
17930 
17931   auto *m = get_message_force(d, full_message_id.get_message_id(), "get_message_embedding_code");
17932   if (m == nullptr) {
17933     promise.set_error(Status::Error(400, "Message not found"));
17934     return {};
17935   }
17936   if (m->message_id.is_yet_unsent()) {
17937     promise.set_error(Status::Error(400, "Message is not sent yet"));
17938     return {};
17939   }
17940   if (m->message_id.is_scheduled()) {
17941     promise.set_error(Status::Error(400, "Message is scheduled"));
17942     return {};
17943   }
17944   if (!m->message_id.is_server()) {
17945     promise.set_error(Status::Error(400, "Message is local"));
17946     return {};
17947   }
17948 
17949   if (m->media_album_id == 0) {
17950     for_group = true;  // default is true
17951   }
17952 
17953   auto &links = message_embedding_codes_[for_group][dialog_id].embedding_codes_;
17954   auto it = links.find(m->message_id);
17955   if (it == links.end()) {
17956     td_->create_handler<ExportChannelMessageLinkQuery>(std::move(promise))
17957         ->send(dialog_id.get_channel_id(), m->message_id, for_group, false);
17958     return {};
17959   }
17960 
17961   promise.set_value(Unit());
17962   return it->second;
17963 }
17964 
on_get_public_message_link(FullMessageId full_message_id,bool for_group,string url,string html)17965 void MessagesManager::on_get_public_message_link(FullMessageId full_message_id, bool for_group, string url,
17966                                                  string html) {
17967   LOG_IF(ERROR, url.empty() && html.empty()) << "Receive empty public link for " << full_message_id;
17968   auto dialog_id = full_message_id.get_dialog_id();
17969   auto message_id = full_message_id.get_message_id();
17970   message_embedding_codes_[for_group][dialog_id].embedding_codes_[message_id] = std::move(html);
17971 }
17972 
get_message_link_info(Slice url,Promise<MessageLinkInfo> && promise)17973 void MessagesManager::get_message_link_info(Slice url, Promise<MessageLinkInfo> &&promise) {
17974   auto r_message_link_info = LinkManager::get_message_link_info(url);
17975   if (r_message_link_info.is_error()) {
17976     return promise.set_error(Status::Error(400, r_message_link_info.error().message()));
17977   }
17978 
17979   auto info = r_message_link_info.move_as_ok();
17980   CHECK(info.username.empty() == info.channel_id.is_valid());
17981 
17982   bool have_dialog = info.username.empty() ? td_->contacts_manager_->have_channel_force(info.channel_id)
17983                                            : resolve_dialog_username(info.username).is_valid();
17984   if (!have_dialog) {
17985     auto query_promise = PromiseCreator::lambda(
17986         [actor_id = actor_id(this), info, promise = std::move(promise)](Result<Unit> &&result) mutable {
17987           if (result.is_error()) {
17988             return promise.set_value(std::move(info));
17989           }
17990           send_closure(actor_id, &MessagesManager::on_get_message_link_dialog, std::move(info), std::move(promise));
17991         });
17992     if (info.username.empty()) {
17993       td_->contacts_manager_->reload_channel(info.channel_id, std::move(query_promise));
17994     } else {
17995       td_->create_handler<ResolveUsernameQuery>(std::move(query_promise))->send(info.username);
17996     }
17997     return;
17998   }
17999 
18000   return on_get_message_link_dialog(std::move(info), std::move(promise));
18001 }
18002 
on_get_message_link_dialog(MessageLinkInfo && info,Promise<MessageLinkInfo> && promise)18003 void MessagesManager::on_get_message_link_dialog(MessageLinkInfo &&info, Promise<MessageLinkInfo> &&promise) {
18004   TRY_STATUS_PROMISE(promise, G()->close_status());
18005 
18006   DialogId dialog_id;
18007   if (info.username.empty()) {
18008     if (!td_->contacts_manager_->have_channel(info.channel_id)) {
18009       return promise.set_error(Status::Error(500, "Chat info not found"));
18010     }
18011 
18012     dialog_id = DialogId(info.channel_id);
18013     force_create_dialog(dialog_id, "on_get_message_link_dialog");
18014   } else {
18015     dialog_id = resolve_dialog_username(info.username);
18016     if (dialog_id.is_valid()) {
18017       force_create_dialog(dialog_id, "on_get_message_link_dialog", true);
18018     }
18019   }
18020   Dialog *d = get_dialog_force(dialog_id, "on_get_message_link_dialog");
18021   if (d == nullptr) {
18022     return promise.set_error(Status::Error(500, "Chat not found"));
18023   }
18024 
18025   auto message_id = info.message_id;
18026   get_message_force_from_server(d, message_id,
18027                                 PromiseCreator::lambda([actor_id = actor_id(this), info = std::move(info), dialog_id,
18028                                                         promise = std::move(promise)](Result<Unit> &&result) mutable {
18029                                   if (result.is_error()) {
18030                                     return promise.set_value(std::move(info));
18031                                   }
18032                                   send_closure(actor_id, &MessagesManager::on_get_message_link_message, std::move(info),
18033                                                dialog_id, std::move(promise));
18034                                 }));
18035 }
18036 
on_get_message_link_message(MessageLinkInfo && info,DialogId dialog_id,Promise<MessageLinkInfo> && promise)18037 void MessagesManager::on_get_message_link_message(MessageLinkInfo &&info, DialogId dialog_id,
18038                                                   Promise<MessageLinkInfo> &&promise) {
18039   TRY_STATUS_PROMISE(promise, G()->close_status());
18040 
18041   auto message_id = info.message_id;
18042   Message *m = get_message_force({dialog_id, message_id}, "on_get_message_link_message");
18043   if (info.comment_message_id == MessageId() || m == nullptr || !is_broadcast_channel(dialog_id) ||
18044       !m->reply_info.is_comment || !is_active_message_reply_info(dialog_id, m->reply_info)) {
18045     return promise.set_value(std::move(info));
18046   }
18047 
18048   if (td_->contacts_manager_->have_channel_force(m->reply_info.channel_id)) {
18049     force_create_dialog(DialogId(m->reply_info.channel_id), "on_get_message_link_message");
18050     on_get_message_link_discussion_message(std::move(info), DialogId(m->reply_info.channel_id), std::move(promise));
18051     return;
18052   }
18053 
18054   auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), info = std::move(info),
18055                                                promise = std::move(promise)](Result<MessageThreadInfo> result) mutable {
18056     if (result.is_error() || result.ok().message_ids.empty()) {
18057       return promise.set_value(std::move(info));
18058     }
18059     send_closure(actor_id, &MessagesManager::on_get_message_link_discussion_message, std::move(info),
18060                  result.ok().dialog_id, std::move(promise));
18061   });
18062 
18063   td_->create_handler<GetDiscussionMessageQuery>(std::move(query_promise))
18064       ->send(dialog_id, message_id, DialogId(m->reply_info.channel_id), MessageId());
18065 }
18066 
on_get_message_link_discussion_message(MessageLinkInfo && info,DialogId comment_dialog_id,Promise<MessageLinkInfo> && promise)18067 void MessagesManager::on_get_message_link_discussion_message(MessageLinkInfo &&info, DialogId comment_dialog_id,
18068                                                              Promise<MessageLinkInfo> &&promise) {
18069   TRY_STATUS_PROMISE(promise, G()->close_status());
18070 
18071   CHECK(comment_dialog_id.is_valid());
18072   info.comment_dialog_id = comment_dialog_id;
18073 
18074   Dialog *d = get_dialog_force(comment_dialog_id, "on_get_message_link_discussion_message");
18075   if (d == nullptr) {
18076     return promise.set_error(Status::Error(500, "Chat not found"));
18077   }
18078 
18079   auto comment_message_id = info.comment_message_id;
18080   get_message_force_from_server(
18081       d, comment_message_id,
18082       PromiseCreator::lambda([info = std::move(info), promise = std::move(promise)](Result<Unit> &&result) mutable {
18083         return promise.set_value(std::move(info));
18084       }));
18085 }
18086 
get_message_link_info_object(const MessageLinkInfo & info) const18087 td_api::object_ptr<td_api::messageLinkInfo> MessagesManager::get_message_link_info_object(
18088     const MessageLinkInfo &info) const {
18089   CHECK(info.username.empty() == info.channel_id.is_valid());
18090 
18091   bool is_public = !info.username.empty();
18092   DialogId dialog_id = info.comment_dialog_id.is_valid()
18093                            ? info.comment_dialog_id
18094                            : (is_public ? resolve_dialog_username(info.username) : DialogId(info.channel_id));
18095   MessageId message_id = info.comment_dialog_id.is_valid() ? info.comment_message_id : info.message_id;
18096   td_api::object_ptr<td_api::message> message;
18097   int32 media_timestamp = 0;
18098   bool for_album = false;
18099   bool for_comment = false;
18100 
18101   const Dialog *d = get_dialog(dialog_id);
18102   if (d == nullptr) {
18103     dialog_id = DialogId();
18104   } else {
18105     const Message *m = get_message(d, message_id);
18106     if (m != nullptr) {
18107       message = get_message_object(dialog_id, m, "get_message_link_info_object");
18108       for_album = !info.is_single && m->media_album_id != 0;
18109       for_comment = (info.comment_dialog_id.is_valid() || info.for_comment) && m->top_thread_message_id.is_valid();
18110       if (can_message_content_have_media_timestamp(m->content.get())) {
18111         auto duration = get_message_content_media_duration(m->content.get(), td_);
18112         if (duration == 0 || info.media_timestamp <= duration) {
18113           media_timestamp = info.media_timestamp;
18114         }
18115       }
18116     }
18117   }
18118 
18119   return td_api::make_object<td_api::messageLinkInfo>(is_public, dialog_id.get(), std::move(message), media_timestamp,
18120                                                       for_album, for_comment);
18121 }
18122 
get_input_dialog_id(DialogId dialog_id) const18123 InputDialogId MessagesManager::get_input_dialog_id(DialogId dialog_id) const {
18124   auto input_peer = get_input_peer(dialog_id, AccessRights::Read);
18125   if (input_peer == nullptr || input_peer->get_id() == telegram_api::inputPeerSelf::ID) {
18126     return InputDialogId(dialog_id);
18127   } else {
18128     return InputDialogId(input_peer);
18129   }
18130 }
18131 
sort_dialog_filter_input_dialog_ids(DialogFilter * dialog_filter,const char * source) const18132 void MessagesManager::sort_dialog_filter_input_dialog_ids(DialogFilter *dialog_filter, const char *source) const {
18133   auto sort_input_dialog_ids = [contacts_manager =
18134                                     td_->contacts_manager_.get()](vector<InputDialogId> &input_dialog_ids) {
18135     std::sort(input_dialog_ids.begin(), input_dialog_ids.end(),
18136               [contacts_manager](InputDialogId lhs, InputDialogId rhs) {
18137                 auto get_order = [contacts_manager](InputDialogId input_dialog_id) {
18138                   auto dialog_id = input_dialog_id.get_dialog_id();
18139                   if (dialog_id.get_type() != DialogType::SecretChat) {
18140                     return dialog_id.get() * 10;
18141                   }
18142                   auto user_id = contacts_manager->get_secret_chat_user_id(dialog_id.get_secret_chat_id());
18143                   return DialogId(user_id).get() * 10 + 1;
18144                 };
18145                 return get_order(lhs) < get_order(rhs);
18146               });
18147   };
18148 
18149   if (!dialog_filter->include_contacts && !dialog_filter->include_non_contacts && !dialog_filter->include_bots &&
18150       !dialog_filter->include_groups && !dialog_filter->include_channels) {
18151     dialog_filter->excluded_dialog_ids.clear();
18152   }
18153 
18154   sort_input_dialog_ids(dialog_filter->excluded_dialog_ids);
18155   sort_input_dialog_ids(dialog_filter->included_dialog_ids);
18156 
18157   std::unordered_set<DialogId, DialogIdHash> all_dialog_ids;
18158   for (auto input_dialog_ids :
18159        {&dialog_filter->pinned_dialog_ids, &dialog_filter->excluded_dialog_ids, &dialog_filter->included_dialog_ids}) {
18160     for (const auto &input_dialog_id : *input_dialog_ids) {
18161       LOG_CHECK(all_dialog_ids.insert(input_dialog_id.get_dialog_id()).second)
18162           << source << ' ' << input_dialog_id.get_dialog_id() << ' ' << dialog_filter;
18163     }
18164   }
18165 }
18166 
create_dialog_filter(DialogFilterId dialog_filter_id,td_api::object_ptr<td_api::chatFilter> filter)18167 Result<unique_ptr<DialogFilter>> MessagesManager::create_dialog_filter(DialogFilterId dialog_filter_id,
18168                                                                        td_api::object_ptr<td_api::chatFilter> filter) {
18169   CHECK(filter != nullptr);
18170   for (auto chat_ids : {&filter->pinned_chat_ids_, &filter->excluded_chat_ids_, &filter->included_chat_ids_}) {
18171     for (const auto &chat_id : *chat_ids) {
18172       DialogId dialog_id(chat_id);
18173       if (!dialog_id.is_valid()) {
18174         return Status::Error(400, "Invalid chat identifier specified");
18175       }
18176       const Dialog *d = get_dialog_force(dialog_id, "create_dialog_filter");
18177       if (d == nullptr) {
18178         return Status::Error(400, "Chat not found");
18179       }
18180       if (!have_input_peer(dialog_id, AccessRights::Read)) {
18181         return Status::Error(400, "Can't access the chat");
18182       }
18183       if (d->order == DEFAULT_ORDER) {
18184         return Status::Error(400, "Chat is not in the chat list");
18185       }
18186     }
18187   }
18188 
18189   auto dialog_filter = make_unique<DialogFilter>();
18190   dialog_filter->dialog_filter_id = dialog_filter_id;
18191 
18192   std::unordered_set<int64> added_dialog_ids;
18193   auto add_chats = [this, &added_dialog_ids](vector<InputDialogId> &input_dialog_ids, const vector<int64> &chat_ids) {
18194     for (const auto &chat_id : chat_ids) {
18195       if (!added_dialog_ids.insert(chat_id).second) {
18196         // do not allow duplicate chat_ids
18197         continue;
18198       }
18199 
18200       input_dialog_ids.push_back(get_input_dialog_id(DialogId(chat_id)));
18201     }
18202   };
18203   add_chats(dialog_filter->pinned_dialog_ids, filter->pinned_chat_ids_);
18204   add_chats(dialog_filter->included_dialog_ids, filter->included_chat_ids_);
18205   add_chats(dialog_filter->excluded_dialog_ids, filter->excluded_chat_ids_);
18206 
18207   dialog_filter->title = clean_name(std::move(filter->title_), MAX_DIALOG_FILTER_TITLE_LENGTH);
18208   if (dialog_filter->title.empty()) {
18209     return Status::Error(400, "Title must be non-empty");
18210   }
18211   dialog_filter->emoji = DialogFilter::get_emoji_by_icon_name(filter->icon_name_);
18212   if (dialog_filter->emoji.empty() && !filter->icon_name_.empty()) {
18213     return Status::Error(400, "Invalid icon name specified");
18214   }
18215   dialog_filter->exclude_muted = filter->exclude_muted_;
18216   dialog_filter->exclude_read = filter->exclude_read_;
18217   dialog_filter->exclude_archived = filter->exclude_archived_;
18218   dialog_filter->include_contacts = filter->include_contacts_;
18219   dialog_filter->include_non_contacts = filter->include_non_contacts_;
18220   dialog_filter->include_bots = filter->include_bots_;
18221   dialog_filter->include_groups = filter->include_groups_;
18222   dialog_filter->include_channels = filter->include_channels_;
18223 
18224   TRY_STATUS(dialog_filter->check_limits());
18225   sort_dialog_filter_input_dialog_ids(dialog_filter.get(), "create_dialog_filter");
18226 
18227   return std::move(dialog_filter);
18228 }
18229 
create_dialog_filter(td_api::object_ptr<td_api::chatFilter> filter,Promise<td_api::object_ptr<td_api::chatFilterInfo>> && promise)18230 void MessagesManager::create_dialog_filter(td_api::object_ptr<td_api::chatFilter> filter,
18231                                            Promise<td_api::object_ptr<td_api::chatFilterInfo>> &&promise) {
18232   CHECK(!td_->auth_manager_->is_bot());
18233   if (dialog_filters_.size() >= MAX_DIALOG_FILTERS) {
18234     return promise.set_error(Status::Error(400, "The maximum number of chat folders exceeded"));
18235   }
18236   if (!is_update_chat_filters_sent_) {
18237     return promise.set_error(Status::Error(400, "Chat folders are not synchronized yet"));
18238   }
18239 
18240   DialogFilterId dialog_filter_id;
18241   do {
18242     auto min_id = static_cast<int>(DialogFilterId::min().get());
18243     auto max_id = static_cast<int>(DialogFilterId::max().get());
18244     dialog_filter_id = DialogFilterId(static_cast<int32>(Random::fast(min_id, max_id)));
18245   } while (get_dialog_filter(dialog_filter_id) != nullptr || get_server_dialog_filter(dialog_filter_id) != nullptr);
18246 
18247   auto r_dialog_filter = create_dialog_filter(dialog_filter_id, std::move(filter));
18248   if (r_dialog_filter.is_error()) {
18249     return promise.set_error(r_dialog_filter.move_as_error());
18250   }
18251   auto dialog_filter = r_dialog_filter.move_as_ok();
18252   CHECK(dialog_filter != nullptr);
18253   auto chat_filter_info = dialog_filter->get_chat_filter_info_object();
18254 
18255   bool at_beginning = false;
18256   for (const auto &recommended_dialog_filter : recommended_dialog_filters_) {
18257     if (DialogFilter::are_similar(*recommended_dialog_filter.dialog_filter, *dialog_filter)) {
18258       at_beginning = true;
18259     }
18260   }
18261 
18262   add_dialog_filter(std::move(dialog_filter), at_beginning, "create_dialog_filter");
18263   save_dialog_filters();
18264   send_update_chat_filters();
18265 
18266   synchronize_dialog_filters();
18267   promise.set_value(std::move(chat_filter_info));
18268 }
18269 
edit_dialog_filter(DialogFilterId dialog_filter_id,td_api::object_ptr<td_api::chatFilter> filter,Promise<td_api::object_ptr<td_api::chatFilterInfo>> && promise)18270 void MessagesManager::edit_dialog_filter(DialogFilterId dialog_filter_id, td_api::object_ptr<td_api::chatFilter> filter,
18271                                          Promise<td_api::object_ptr<td_api::chatFilterInfo>> &&promise) {
18272   CHECK(!td_->auth_manager_->is_bot());
18273   auto old_dialog_filter = get_dialog_filter(dialog_filter_id);
18274   if (old_dialog_filter == nullptr) {
18275     return promise.set_error(Status::Error(400, "Chat filter not found"));
18276   }
18277   CHECK(is_update_chat_filters_sent_);
18278 
18279   auto r_dialog_filter = create_dialog_filter(dialog_filter_id, std::move(filter));
18280   if (r_dialog_filter.is_error()) {
18281     return promise.set_error(r_dialog_filter.move_as_error());
18282   }
18283   auto new_dialog_filter = r_dialog_filter.move_as_ok();
18284   CHECK(new_dialog_filter != nullptr);
18285   auto chat_filter_info = new_dialog_filter->get_chat_filter_info_object();
18286 
18287   if (*new_dialog_filter == *old_dialog_filter) {
18288     return promise.set_value(std::move(chat_filter_info));
18289   }
18290 
18291   edit_dialog_filter(std::move(new_dialog_filter), "edit_dialog_filter");
18292   save_dialog_filters();
18293   send_update_chat_filters();
18294 
18295   synchronize_dialog_filters();
18296   promise.set_value(std::move(chat_filter_info));
18297 }
18298 
update_dialog_filter_on_server(unique_ptr<DialogFilter> && dialog_filter)18299 void MessagesManager::update_dialog_filter_on_server(unique_ptr<DialogFilter> &&dialog_filter) {
18300   CHECK(!td_->auth_manager_->is_bot());
18301   CHECK(dialog_filter != nullptr);
18302   are_dialog_filters_being_synchronized_ = true;
18303   dialog_filter->remove_secret_chat_dialog_ids();
18304   auto dialog_filter_id = dialog_filter->dialog_filter_id;
18305   auto input_dialog_filter = dialog_filter->get_input_dialog_filter();
18306 
18307   auto promise = PromiseCreator::lambda(
18308       [actor_id = actor_id(this), dialog_filter = std::move(dialog_filter)](Result<Unit> result) mutable {
18309         send_closure(actor_id, &MessagesManager::on_update_dialog_filter, std::move(dialog_filter),
18310                      result.is_error() ? result.move_as_error() : Status::OK());
18311       });
18312   td_->create_handler<UpdateDialogFilterQuery>(std::move(promise))
18313       ->send(dialog_filter_id, std::move(input_dialog_filter));
18314 }
18315 
on_update_dialog_filter(unique_ptr<DialogFilter> dialog_filter,Status result)18316 void MessagesManager::on_update_dialog_filter(unique_ptr<DialogFilter> dialog_filter, Status result) {
18317   CHECK(!td_->auth_manager_->is_bot());
18318   if (result.is_error()) {
18319     // TODO rollback dialog_filters_ changes if error isn't 429
18320   } else {
18321     bool is_edited = false;
18322     for (auto &filter : server_dialog_filters_) {
18323       if (filter->dialog_filter_id == dialog_filter->dialog_filter_id) {
18324         if (*filter != *dialog_filter) {
18325           filter = std::move(dialog_filter);
18326         }
18327         is_edited = true;
18328         break;
18329       }
18330     }
18331 
18332     if (!is_edited) {
18333       server_dialog_filters_.push_back(std::move(dialog_filter));
18334     }
18335     save_dialog_filters();
18336   }
18337 
18338   are_dialog_filters_being_synchronized_ = false;
18339   synchronize_dialog_filters();
18340 }
18341 
delete_dialog_filter(DialogFilterId dialog_filter_id,Promise<Unit> && promise)18342 void MessagesManager::delete_dialog_filter(DialogFilterId dialog_filter_id, Promise<Unit> &&promise) {
18343   CHECK(!td_->auth_manager_->is_bot());
18344   auto dialog_filter = get_dialog_filter(dialog_filter_id);
18345   if (dialog_filter == nullptr) {
18346     return promise.set_value(Unit());
18347   }
18348 
18349   delete_dialog_filter(dialog_filter_id, "delete_dialog_filter");
18350   save_dialog_filters();
18351   send_update_chat_filters();
18352 
18353   synchronize_dialog_filters();
18354   promise.set_value(Unit());
18355 }
18356 
delete_dialog_filter_on_server(DialogFilterId dialog_filter_id)18357 void MessagesManager::delete_dialog_filter_on_server(DialogFilterId dialog_filter_id) {
18358   CHECK(!td_->auth_manager_->is_bot());
18359   are_dialog_filters_being_synchronized_ = true;
18360   auto promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_filter_id](Result<Unit> result) {
18361     send_closure(actor_id, &MessagesManager::on_delete_dialog_filter, dialog_filter_id,
18362                  result.is_error() ? result.move_as_error() : Status::OK());
18363   });
18364   td_->create_handler<UpdateDialogFilterQuery>(std::move(promise))->send(dialog_filter_id, nullptr);
18365 }
18366 
on_delete_dialog_filter(DialogFilterId dialog_filter_id,Status result)18367 void MessagesManager::on_delete_dialog_filter(DialogFilterId dialog_filter_id, Status result) {
18368   CHECK(!td_->auth_manager_->is_bot());
18369   if (result.is_error()) {
18370     // TODO rollback dialog_filters_ changes if error isn't 429
18371   } else {
18372     for (auto it = server_dialog_filters_.begin(); it != server_dialog_filters_.end(); ++it) {
18373       if ((*it)->dialog_filter_id == dialog_filter_id) {
18374         server_dialog_filters_.erase(it);
18375         save_dialog_filters();
18376         break;
18377       }
18378     }
18379   }
18380 
18381   are_dialog_filters_being_synchronized_ = false;
18382   synchronize_dialog_filters();
18383 }
18384 
reorder_dialog_filters(vector<DialogFilterId> dialog_filter_ids,Promise<Unit> && promise)18385 void MessagesManager::reorder_dialog_filters(vector<DialogFilterId> dialog_filter_ids, Promise<Unit> &&promise) {
18386   CHECK(!td_->auth_manager_->is_bot());
18387 
18388   for (auto dialog_filter_id : dialog_filter_ids) {
18389     auto dialog_filter = get_dialog_filter(dialog_filter_id);
18390     if (dialog_filter == nullptr) {
18391       return promise.set_error(Status::Error(400, "Chat filter not found"));
18392     }
18393   }
18394   std::unordered_set<DialogFilterId, DialogFilterIdHash> new_dialog_filter_ids_set(dialog_filter_ids.begin(),
18395                                                                                    dialog_filter_ids.end());
18396   if (new_dialog_filter_ids_set.size() != dialog_filter_ids.size()) {
18397     return promise.set_error(Status::Error(400, "Duplicate chat filters in the new list"));
18398   }
18399 
18400   if (set_dialog_filters_order(dialog_filters_, dialog_filter_ids)) {
18401     save_dialog_filters();
18402     send_update_chat_filters();
18403 
18404     synchronize_dialog_filters();
18405   }
18406   promise.set_value(Unit());
18407 }
18408 
reorder_dialog_filters_on_server(vector<DialogFilterId> dialog_filter_ids)18409 void MessagesManager::reorder_dialog_filters_on_server(vector<DialogFilterId> dialog_filter_ids) {
18410   CHECK(!td_->auth_manager_->is_bot());
18411   are_dialog_filters_being_synchronized_ = true;
18412   auto promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_filter_ids](Result<Unit> result) mutable {
18413     send_closure(actor_id, &MessagesManager::on_reorder_dialog_filters, std::move(dialog_filter_ids),
18414                  result.is_error() ? result.move_as_error() : Status::OK());
18415   });
18416   td_->create_handler<UpdateDialogFiltersOrderQuery>(std::move(promise))->send(dialog_filter_ids);
18417 }
18418 
on_reorder_dialog_filters(vector<DialogFilterId> dialog_filter_ids,Status result)18419 void MessagesManager::on_reorder_dialog_filters(vector<DialogFilterId> dialog_filter_ids, Status result) {
18420   CHECK(!td_->auth_manager_->is_bot());
18421   if (result.is_error()) {
18422     // TODO rollback dialog_filters_ changes if error isn't 429
18423   } else {
18424     if (set_dialog_filters_order(server_dialog_filters_, std::move(dialog_filter_ids))) {
18425       save_dialog_filters();
18426     }
18427   }
18428 
18429   are_dialog_filters_being_synchronized_ = false;
18430   synchronize_dialog_filters();
18431 }
18432 
set_dialog_filters_order(vector<unique_ptr<DialogFilter>> & dialog_filters,vector<DialogFilterId> dialog_filter_ids)18433 bool MessagesManager::set_dialog_filters_order(vector<unique_ptr<DialogFilter>> &dialog_filters,
18434                                                vector<DialogFilterId> dialog_filter_ids) {
18435   auto old_dialog_filter_ids = get_dialog_filter_ids(dialog_filters);
18436   if (old_dialog_filter_ids == dialog_filter_ids) {
18437     return false;
18438   }
18439   LOG(INFO) << "Reorder chat filters from " << old_dialog_filter_ids << " to " << dialog_filter_ids;
18440 
18441   if (dialog_filter_ids.size() != old_dialog_filter_ids.size()) {
18442     for (auto dialog_filter_id : old_dialog_filter_ids) {
18443       if (!td::contains(dialog_filter_ids, dialog_filter_id)) {
18444         dialog_filter_ids.push_back(dialog_filter_id);
18445       }
18446     }
18447     CHECK(dialog_filter_ids.size() == old_dialog_filter_ids.size());
18448   }
18449   if (old_dialog_filter_ids == dialog_filter_ids) {
18450     return false;
18451   }
18452 
18453   CHECK(dialog_filter_ids.size() == dialog_filters.size());
18454   for (size_t i = 0; i < dialog_filters.size(); i++) {
18455     for (size_t j = i; j < dialog_filters.size(); j++) {
18456       if (dialog_filters[j]->dialog_filter_id == dialog_filter_ids[i]) {
18457         if (i != j) {
18458           std::swap(dialog_filters[i], dialog_filters[j]);
18459         }
18460         break;
18461       }
18462     }
18463     CHECK(dialog_filters[i]->dialog_filter_id == dialog_filter_ids[i]);
18464   }
18465   return true;
18466 }
18467 
add_dialog_filter(unique_ptr<DialogFilter> dialog_filter,bool at_beginning,const char * source)18468 void MessagesManager::add_dialog_filter(unique_ptr<DialogFilter> dialog_filter, bool at_beginning, const char *source) {
18469   if (td_->auth_manager_->is_bot()) {
18470     // just in case
18471     return;
18472   }
18473 
18474   CHECK(dialog_filter != nullptr);
18475   auto dialog_filter_id = dialog_filter->dialog_filter_id;
18476   LOG(INFO) << "Add " << dialog_filter_id << " from " << source;
18477   CHECK(get_dialog_filter(dialog_filter_id) == nullptr);
18478   if (at_beginning) {
18479     dialog_filters_.insert(dialog_filters_.begin(), std::move(dialog_filter));
18480   } else {
18481     dialog_filters_.push_back(std::move(dialog_filter));
18482   }
18483 
18484   auto dialog_list_id = DialogListId(dialog_filter_id);
18485   CHECK(dialog_lists_.find(dialog_list_id) == dialog_lists_.end());
18486 
18487   auto &list = add_dialog_list(dialog_list_id);
18488   auto folder_ids = get_dialog_list_folder_ids(list);
18489   CHECK(!folder_ids.empty());
18490 
18491   for (auto folder_id : folder_ids) {
18492     auto *folder = get_dialog_folder(folder_id);
18493     CHECK(folder != nullptr);
18494     for (const auto &dialog_date : folder->ordered_dialogs_) {
18495       if (dialog_date.get_order() == DEFAULT_ORDER) {
18496         break;
18497       }
18498 
18499       auto dialog_id = dialog_date.get_dialog_id();
18500       Dialog *d = get_dialog(dialog_id);
18501       CHECK(d != nullptr);
18502 
18503       if (need_dialog_in_list(d, list)) {
18504         list.in_memory_dialog_total_count_++;
18505 
18506         add_dialog_to_list(d, dialog_list_id);
18507       }
18508     }
18509   }
18510 
18511   for (const auto &input_dialog_id : reversed(dialog_filters_.back()->pinned_dialog_ids)) {
18512     auto dialog_id = input_dialog_id.get_dialog_id();
18513     auto order = get_next_pinned_dialog_order();
18514     list.pinned_dialogs_.emplace_back(order, dialog_id);
18515     list.pinned_dialog_id_orders_.emplace(dialog_id, order);
18516   }
18517   std::reverse(list.pinned_dialogs_.begin(), list.pinned_dialogs_.end());
18518   list.are_pinned_dialogs_inited_ = true;
18519 
18520   update_list_last_pinned_dialog_date(list);
18521   update_list_last_dialog_date(list);
18522 }
18523 
edit_dialog_filter(unique_ptr<DialogFilter> new_dialog_filter,const char * source)18524 void MessagesManager::edit_dialog_filter(unique_ptr<DialogFilter> new_dialog_filter, const char *source) {
18525   if (td_->auth_manager_->is_bot()) {
18526     // just in case
18527     return;
18528   }
18529 
18530   CHECK(new_dialog_filter != nullptr);
18531   LOG(INFO) << "Edit " << new_dialog_filter->dialog_filter_id << " from " << source;
18532   for (auto &old_dialog_filter : dialog_filters_) {
18533     if (old_dialog_filter->dialog_filter_id == new_dialog_filter->dialog_filter_id) {
18534       CHECK(*old_dialog_filter != *new_dialog_filter);
18535 
18536       auto dialog_list_id = DialogListId(old_dialog_filter->dialog_filter_id);
18537       auto *old_list_ptr = get_dialog_list(dialog_list_id);
18538       CHECK(old_list_ptr != nullptr);
18539       auto &old_list = *old_list_ptr;
18540 
18541       disable_get_dialog_filter_ = true;  // to ensure crash if get_dialog_filter is called
18542 
18543       auto folder_ids = get_dialog_filter_folder_ids(old_dialog_filter.get());
18544       CHECK(!folder_ids.empty());
18545       for (auto folder_id : get_dialog_filter_folder_ids(new_dialog_filter.get())) {
18546         if (!td::contains(folder_ids, folder_id)) {
18547           folder_ids.push_back(folder_id);
18548         }
18549       }
18550 
18551       DialogList new_list;
18552       new_list.dialog_list_id = dialog_list_id;
18553 
18554       auto old_it = old_list.pinned_dialogs_.rbegin();
18555       for (const auto &input_dialog_id : reversed(new_dialog_filter->pinned_dialog_ids)) {
18556         auto dialog_id = input_dialog_id.get_dialog_id();
18557         while (old_it < old_list.pinned_dialogs_.rend()) {
18558           if (old_it->get_dialog_id() == dialog_id) {
18559             break;
18560           }
18561           ++old_it;
18562         }
18563 
18564         int64 order;
18565         if (old_it < old_list.pinned_dialogs_.rend()) {
18566           order = old_it->get_order();
18567           ++old_it;
18568         } else {
18569           order = get_next_pinned_dialog_order();
18570         }
18571         new_list.pinned_dialogs_.emplace_back(order, dialog_id);
18572         new_list.pinned_dialog_id_orders_.emplace(dialog_id, order);
18573       }
18574       std::reverse(new_list.pinned_dialogs_.begin(), new_list.pinned_dialogs_.end());
18575       new_list.are_pinned_dialogs_inited_ = true;
18576 
18577       do_update_list_last_pinned_dialog_date(new_list);
18578       do_update_list_last_dialog_date(new_list, get_dialog_filter_folder_ids(new_dialog_filter.get()));
18579 
18580       new_list.server_dialog_total_count_ = 0;
18581       new_list.secret_chat_total_count_ = 0;
18582 
18583       std::map<DialogDate, const Dialog *> updated_position_dialogs;
18584       for (auto folder_id : folder_ids) {
18585         auto *folder = get_dialog_folder(folder_id);
18586         CHECK(folder != nullptr);
18587         for (const auto &dialog_date : folder->ordered_dialogs_) {
18588           if (dialog_date.get_order() == DEFAULT_ORDER) {
18589             break;
18590           }
18591 
18592           auto dialog_id = dialog_date.get_dialog_id();
18593           Dialog *d = get_dialog(dialog_id);
18594           CHECK(d != nullptr);
18595 
18596           const DialogPositionInList old_position = get_dialog_position_in_list(old_list_ptr, d);
18597           // can't use get_dialog_position_in_list, because need_dialog_in_list calls get_dialog_filter
18598           DialogPositionInList new_position;
18599           if (need_dialog_in_filter(d, new_dialog_filter.get())) {
18600             new_position.private_order = get_dialog_private_order(&new_list, d);
18601             if (new_position.private_order != 0) {
18602               new_position.public_order =
18603                   DialogDate(new_position.private_order, dialog_id) <= new_list.list_last_dialog_date_
18604                       ? new_position.private_order
18605                       : 0;
18606               new_position.is_pinned = get_dialog_pinned_order(&new_list, dialog_id) != DEFAULT_ORDER;
18607               new_position.is_sponsored = is_dialog_sponsored(d);
18608             }
18609           }
18610 
18611           if (need_send_update_chat_position(old_position, new_position)) {
18612             updated_position_dialogs.emplace(DialogDate(new_position.public_order, dialog_id), d);
18613           }
18614 
18615           bool was_in_list = old_position.private_order != 0;
18616           bool is_in_list = new_position.private_order != 0;
18617           if (is_in_list) {
18618             if (!was_in_list) {
18619               add_dialog_to_list(d, dialog_list_id);
18620             }
18621 
18622             new_list.in_memory_dialog_total_count_++;
18623             if (dialog_id.get_type() == DialogType::SecretChat) {
18624               new_list.secret_chat_total_count_++;
18625             } else {
18626               new_list.server_dialog_total_count_++;
18627             }
18628 
18629             auto unread_count = d->server_unread_count + d->local_unread_count;
18630             if (unread_count != 0) {
18631               new_list.unread_message_total_count_ += unread_count;
18632               if (is_dialog_muted(d)) {
18633                 new_list.unread_message_muted_count_ += unread_count;
18634               }
18635             }
18636             if (unread_count != 0 || d->is_marked_as_unread) {
18637               new_list.unread_dialog_total_count_++;
18638               if (unread_count == 0 && d->is_marked_as_unread) {
18639                 new_list.unread_dialog_marked_count_++;
18640               }
18641               if (is_dialog_muted(d)) {
18642                 new_list.unread_dialog_muted_count_++;
18643                 if (unread_count == 0 && d->is_marked_as_unread) {
18644                   new_list.unread_dialog_muted_marked_count_++;
18645                 }
18646               }
18647             }
18648           } else {
18649             if (was_in_list) {
18650               remove_dialog_from_list(d, dialog_list_id);
18651             }
18652           }
18653         }
18654       }
18655 
18656       if (new_list.list_last_dialog_date_ == MAX_DIALOG_DATE) {
18657         new_list.is_message_unread_count_inited_ = true;
18658         new_list.is_dialog_unread_count_inited_ = true;
18659         new_list.need_unread_count_recalc_ = false;
18660       } else {
18661         if (old_list.is_message_unread_count_inited_) {  // can't stop sending updates
18662           new_list.is_message_unread_count_inited_ = true;
18663         }
18664         if (old_list.is_dialog_unread_count_inited_) {  // can't stop sending updates
18665           new_list.is_dialog_unread_count_inited_ = true;
18666         }
18667         new_list.server_dialog_total_count_ = -1;
18668         new_list.secret_chat_total_count_ = -1;
18669       }
18670 
18671       bool need_update_unread_message_count =
18672           new_list.is_message_unread_count_inited_ &&
18673           (old_list.unread_message_total_count_ != new_list.unread_message_total_count_ ||
18674            old_list.unread_message_muted_count_ != new_list.unread_message_muted_count_ ||
18675            !old_list.is_message_unread_count_inited_);
18676       bool need_update_unread_chat_count =
18677           new_list.is_dialog_unread_count_inited_ &&
18678           (old_list.unread_dialog_total_count_ != new_list.unread_dialog_total_count_ ||
18679            old_list.unread_dialog_muted_count_ != new_list.unread_dialog_muted_count_ ||
18680            old_list.unread_dialog_marked_count_ != new_list.unread_dialog_marked_count_ ||
18681            old_list.unread_dialog_muted_marked_count_ != new_list.unread_dialog_muted_marked_count_ ||
18682            get_dialog_total_count(old_list) != get_dialog_total_count(new_list) ||
18683            !old_list.is_dialog_unread_count_inited_);
18684       bool need_save_unread_chat_count = new_list.is_dialog_unread_count_inited_ &&
18685                                          (old_list.server_dialog_total_count_ != new_list.server_dialog_total_count_ ||
18686                                           old_list.secret_chat_total_count_ != new_list.secret_chat_total_count_);
18687 
18688       auto load_list_promises = std::move(old_list.load_list_queries_);
18689 
18690       disable_get_dialog_filter_ = false;
18691 
18692       old_list = std::move(new_list);
18693       old_dialog_filter = std::move(new_dialog_filter);
18694 
18695       if (need_update_unread_message_count) {
18696         send_update_unread_message_count(old_list, DialogId(), true, source);
18697       }
18698       if (need_update_unread_chat_count) {
18699         send_update_unread_chat_count(old_list, DialogId(), true, source);
18700       } else if (need_save_unread_chat_count) {
18701         save_unread_chat_count(old_list);
18702       }
18703 
18704       for (const auto &it : updated_position_dialogs) {
18705         send_update_chat_position(dialog_list_id, it.second, source);
18706       }
18707 
18708       if (old_list.need_unread_count_recalc_) {
18709         // repair unread count
18710         get_dialogs_from_list(dialog_list_id, static_cast<int32>(old_list.pinned_dialogs_.size() + 2), Auto());
18711       }
18712 
18713       if (!load_list_promises.empty()) {
18714         LOG(INFO) << "Retry loading of chats in " << dialog_list_id;
18715         for (auto &promise : load_list_promises) {
18716           promise.set_value(Unit());  // try again
18717         }
18718       }
18719       return;
18720     }
18721   }
18722   UNREACHABLE();
18723 }
18724 
delete_dialog_filter(DialogFilterId dialog_filter_id,const char * source)18725 void MessagesManager::delete_dialog_filter(DialogFilterId dialog_filter_id, const char *source) {
18726   if (td_->auth_manager_->is_bot()) {
18727     // just in case
18728     return;
18729   }
18730 
18731   LOG(INFO) << "Delete " << dialog_filter_id << " from " << source;
18732   for (auto it = dialog_filters_.begin(); it != dialog_filters_.end(); ++it) {
18733     if ((*it)->dialog_filter_id == dialog_filter_id) {
18734       auto dialog_list_id = DialogListId(dialog_filter_id);
18735       auto *list = get_dialog_list(dialog_list_id);
18736       CHECK(list != nullptr);
18737       auto folder_ids = get_dialog_list_folder_ids(*list);
18738       CHECK(!folder_ids.empty());
18739 
18740       for (auto folder_id : folder_ids) {
18741         auto *folder = get_dialog_folder(folder_id);
18742         CHECK(folder != nullptr);
18743         for (const auto &dialog_date : folder->ordered_dialogs_) {
18744           if (dialog_date.get_order() == DEFAULT_ORDER) {
18745             break;
18746           }
18747 
18748           auto dialog_id = dialog_date.get_dialog_id();
18749           Dialog *d = get_dialog(dialog_id);
18750           CHECK(d != nullptr);
18751 
18752           const DialogPositionInList old_position = get_dialog_position_in_list(list, d);
18753 
18754           if (is_dialog_in_list(d, dialog_list_id)) {
18755             remove_dialog_from_list(d, dialog_list_id);
18756 
18757             if (old_position.public_order != 0) {
18758               send_update_chat_position(dialog_list_id, d, source);
18759             }
18760           }
18761         }
18762       }
18763 
18764       if (G()->parameters().use_message_db) {
18765         postponed_unread_message_count_updates_.erase(dialog_list_id);
18766         postponed_unread_chat_count_updates_.erase(dialog_list_id);
18767 
18768         if (list->is_message_unread_count_inited_) {
18769           list->unread_message_total_count_ = 0;
18770           list->unread_message_muted_count_ = 0;
18771           send_update_unread_message_count(*list, DialogId(), true, source, true);
18772           G()->td_db()->get_binlog_pmc()->erase(PSTRING() << "unread_message_count" << dialog_list_id.get());
18773         }
18774         if (list->is_dialog_unread_count_inited_) {
18775           list->unread_dialog_total_count_ = 0;
18776           list->unread_dialog_muted_count_ = 0;
18777           list->unread_dialog_marked_count_ = 0;
18778           list->unread_dialog_muted_marked_count_ = 0;
18779           list->in_memory_dialog_total_count_ = 0;
18780           list->server_dialog_total_count_ = 0;
18781           list->secret_chat_total_count_ = 0;
18782           send_update_unread_chat_count(*list, DialogId(), true, source, true);
18783           G()->td_db()->get_binlog_pmc()->erase(PSTRING() << "unread_dialog_count" << dialog_list_id.get());
18784         }
18785       }
18786 
18787       auto promises = std::move(list->load_list_queries_);
18788       for (auto &promise : promises) {
18789         promise.set_error(Status::Error(400, "Chat list not found"));
18790       }
18791 
18792       dialog_lists_.erase(dialog_list_id);
18793       dialog_filters_.erase(it);
18794       return;
18795     }
18796   }
18797   UNREACHABLE();
18798 }
18799 
delete_dialog_reply_markup(DialogId dialog_id,MessageId message_id)18800 Status MessagesManager::delete_dialog_reply_markup(DialogId dialog_id, MessageId message_id) {
18801   if (td_->auth_manager_->is_bot()) {
18802     return Status::Error(400, "Bots can't delete chat reply markup");
18803   }
18804   if (message_id.is_scheduled()) {
18805     return Status::Error(400, "Wrong message identifier specified");
18806   }
18807   if (!message_id.is_valid()) {
18808     return Status::Error(400, "Invalid message identifier specified");
18809   }
18810 
18811   Dialog *d = get_dialog_force(dialog_id, "delete_dialog_reply_markup");
18812   if (d == nullptr) {
18813     return Status::Error(400, "Chat not found");
18814   }
18815   if (d->reply_markup_message_id != message_id) {
18816     return Status::OK();
18817   }
18818 
18819   Message *m = get_message_force(d, message_id, "delete_dialog_reply_markup");
18820   CHECK(m != nullptr);
18821   CHECK(m->reply_markup != nullptr);
18822 
18823   if (m->reply_markup->type == ReplyMarkup::Type::ForceReply) {
18824     set_dialog_reply_markup(d, MessageId());
18825   } else if (m->reply_markup->type == ReplyMarkup::Type::ShowKeyboard) {
18826     if (!m->reply_markup->is_one_time_keyboard) {
18827       return Status::Error(400, "Do not need to delete non one-time keyboard");
18828     }
18829     if (m->reply_markup->is_personal) {
18830       m->reply_markup->is_personal = false;
18831       set_dialog_reply_markup(d, message_id);
18832 
18833       on_message_changed(d, m, true, "delete_dialog_reply_markup");
18834     }
18835   } else {
18836     // non-bots can't have messages with RemoveKeyboard
18837     UNREACHABLE();
18838   }
18839   return Status::OK();
18840 }
18841 
18842 class MessagesManager::SaveDialogDraftMessageOnServerLogEvent {
18843  public:
18844   DialogId dialog_id_;
18845 
18846   template <class StorerT>
store(StorerT & storer) const18847   void store(StorerT &storer) const {
18848     td::store(dialog_id_, storer);
18849   }
18850 
18851   template <class ParserT>
parse(ParserT & parser)18852   void parse(ParserT &parser) {
18853     td::parse(dialog_id_, parser);
18854   }
18855 };
18856 
set_dialog_draft_message(DialogId dialog_id,MessageId top_thread_message_id,tl_object_ptr<td_api::draftMessage> && draft_message)18857 Status MessagesManager::set_dialog_draft_message(DialogId dialog_id, MessageId top_thread_message_id,
18858                                                  tl_object_ptr<td_api::draftMessage> &&draft_message) {
18859   if (td_->auth_manager_->is_bot()) {
18860     return Status::Error(400, "Bots can't change chat draft message");
18861   }
18862 
18863   Dialog *d = get_dialog_force(dialog_id, "set_dialog_draft_message");
18864   if (d == nullptr) {
18865     return Status::Error(400, "Chat not found");
18866   }
18867   TRY_STATUS(can_send_message(dialog_id));
18868 
18869   TRY_RESULT(new_draft_message, get_draft_message(td_->contacts_manager_.get(), dialog_id, std::move(draft_message)));
18870   if (new_draft_message != nullptr) {
18871     new_draft_message->reply_to_message_id =
18872         get_reply_to_message_id(d, top_thread_message_id, new_draft_message->reply_to_message_id, true);
18873 
18874     if (!new_draft_message->reply_to_message_id.is_valid() && new_draft_message->input_message_text.text.text.empty()) {
18875       new_draft_message = nullptr;
18876     }
18877   }
18878 
18879   if (top_thread_message_id != MessageId()) {
18880     if (!top_thread_message_id.is_valid()) {
18881       return Status::Error(400, "Invalid message thread specified");
18882     }
18883 
18884     auto m = get_message_force(d, top_thread_message_id, "set_dialog_draft_message");
18885     if (m == nullptr || m->message_id.is_scheduled() || m->reply_info.is_comment ||
18886         !is_active_message_reply_info(dialog_id, m->reply_info)) {
18887       return Status::OK();
18888     }
18889 
18890     auto &old_draft_message = m->thread_draft_message;
18891     if (((new_draft_message == nullptr) != (old_draft_message == nullptr)) ||
18892         (new_draft_message != nullptr &&
18893          (old_draft_message->reply_to_message_id != new_draft_message->reply_to_message_id ||
18894           old_draft_message->input_message_text != new_draft_message->input_message_text))) {
18895       old_draft_message = std::move(new_draft_message);
18896       on_message_changed(d, m, false, "set_dialog_draft_message");
18897     }
18898     return Status::OK();
18899   }
18900 
18901   if (update_dialog_draft_message(d, std::move(new_draft_message), false, true)) {
18902     if (dialog_id.get_type() != DialogType::SecretChat) {
18903       if (G()->parameters().use_message_db) {
18904         SaveDialogDraftMessageOnServerLogEvent log_event;
18905         log_event.dialog_id_ = dialog_id;
18906         add_log_event(d->save_draft_message_log_event_id, get_log_event_storer(log_event),
18907                       LogEvent::HandlerType::SaveDialogDraftMessageOnServer, "draft");
18908       }
18909 
18910       pending_draft_message_timeout_.set_timeout_in(dialog_id.get(), d->is_opened ? MIN_SAVE_DRAFT_DELAY : 0);
18911     }
18912   }
18913   return Status::OK();
18914 }
18915 
save_dialog_draft_message_on_server(DialogId dialog_id)18916 void MessagesManager::save_dialog_draft_message_on_server(DialogId dialog_id) {
18917   if (G()->close_flag()) {
18918     return;
18919   }
18920 
18921   auto d = get_dialog(dialog_id);
18922   CHECK(d != nullptr);
18923 
18924   Promise<> promise;
18925   if (d->save_draft_message_log_event_id.log_event_id != 0) {
18926     d->save_draft_message_log_event_id.generation++;
18927     promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_id,
18928                                       generation = d->save_draft_message_log_event_id.generation](Result<Unit> result) {
18929       if (!G()->close_flag()) {
18930         send_closure(actor_id, &MessagesManager::on_saved_dialog_draft_message, dialog_id, generation);
18931       }
18932     });
18933   }
18934 
18935   // TODO do not send two queries simultaneously or use SequenceDispatcher
18936   td_->create_handler<SaveDraftMessageQuery>(std::move(promise))->send(dialog_id, d->draft_message);
18937 }
18938 
on_saved_dialog_draft_message(DialogId dialog_id,uint64 generation)18939 void MessagesManager::on_saved_dialog_draft_message(DialogId dialog_id, uint64 generation) {
18940   auto d = get_dialog(dialog_id);
18941   CHECK(d != nullptr);
18942   delete_log_event(d->save_draft_message_log_event_id, generation, "draft");
18943 }
18944 
clear_all_draft_messages(bool exclude_secret_chats,Promise<Unit> && promise)18945 void MessagesManager::clear_all_draft_messages(bool exclude_secret_chats, Promise<Unit> &&promise) {
18946   if (!exclude_secret_chats) {
18947     for (auto &dialog : dialogs_) {
18948       Dialog *d = dialog.second.get();
18949       if (d->dialog_id.get_type() == DialogType::SecretChat) {
18950         update_dialog_draft_message(d, nullptr, false, true);
18951       }
18952     }
18953   }
18954   td_->create_handler<ClearAllDraftsQuery>(std::move(promise))->send();
18955 }
18956 
get_pinned_dialogs_limit(DialogListId dialog_list_id)18957 int32 MessagesManager::get_pinned_dialogs_limit(DialogListId dialog_list_id) {
18958   if (dialog_list_id.is_filter()) {
18959     return DialogFilter::MAX_INCLUDED_FILTER_DIALOGS;
18960   }
18961 
18962   Slice key{"pinned_chat_count_max"};
18963   int32 default_limit = 5;
18964   if (!dialog_list_id.is_folder() || dialog_list_id.get_folder_id() != FolderId::main()) {
18965     key = Slice("pinned_archived_chat_count_max");
18966     default_limit = 100;
18967   }
18968   int32 limit = clamp(narrow_cast<int32>(G()->shared_config().get_option_integer(key)), 0, 1000);
18969   if (limit <= 0) {
18970     return default_limit;
18971   }
18972   return limit;
18973 }
18974 
remove_secret_chat_dialog_ids(vector<DialogId> dialog_ids)18975 vector<DialogId> MessagesManager::remove_secret_chat_dialog_ids(vector<DialogId> dialog_ids) {
18976   td::remove_if(dialog_ids, [](DialogId dialog_id) { return dialog_id.get_type() == DialogType::SecretChat; });
18977   return dialog_ids;
18978 }
18979 
toggle_dialog_is_pinned(DialogListId dialog_list_id,DialogId dialog_id,bool is_pinned)18980 Status MessagesManager::toggle_dialog_is_pinned(DialogListId dialog_list_id, DialogId dialog_id, bool is_pinned) {
18981   if (td_->auth_manager_->is_bot()) {
18982     return Status::Error(400, "Bots can't change chat pin state");
18983   }
18984 
18985   Dialog *d = get_dialog_force(dialog_id, "toggle_dialog_is_pinned");
18986   if (d == nullptr) {
18987     return Status::Error(400, "Chat not found");
18988   }
18989   if (!have_input_peer(dialog_id, AccessRights::Read)) {
18990     return Status::Error(400, "Can't access the chat");
18991   }
18992   if (d->order == DEFAULT_ORDER && is_pinned) {
18993     return Status::Error(400, "The chat can't be pinned");
18994   }
18995 
18996   auto *list = get_dialog_list(dialog_list_id);
18997   if (list == nullptr) {
18998     return Status::Error(400, "Chat list not found");
18999   }
19000   if (!list->are_pinned_dialogs_inited_) {
19001     return Status::Error(400, "Pinned chats must be loaded first");
19002   }
19003 
19004   bool was_pinned = is_dialog_pinned(dialog_list_id, dialog_id);
19005   if (is_pinned == was_pinned) {
19006     return Status::OK();
19007   }
19008 
19009   if (dialog_list_id.is_filter()) {
19010     CHECK(is_update_chat_filters_sent_);
19011     auto dialog_filter_id = dialog_list_id.get_filter_id();
19012     auto old_dialog_filter = get_dialog_filter(dialog_filter_id);
19013     CHECK(old_dialog_filter != nullptr);
19014     auto new_dialog_filter = make_unique<DialogFilter>(*old_dialog_filter);
19015     auto is_changed_dialog = [dialog_id](InputDialogId input_dialog_id) {
19016       return dialog_id == input_dialog_id.get_dialog_id();
19017     };
19018     if (is_pinned) {
19019       new_dialog_filter->pinned_dialog_ids.insert(new_dialog_filter->pinned_dialog_ids.begin(),
19020                                                   get_input_dialog_id(dialog_id));
19021       td::remove_if(new_dialog_filter->included_dialog_ids, is_changed_dialog);
19022       td::remove_if(new_dialog_filter->excluded_dialog_ids, is_changed_dialog);
19023     } else {
19024       bool is_removed = td::remove_if(new_dialog_filter->pinned_dialog_ids, is_changed_dialog);
19025       CHECK(is_removed);
19026       new_dialog_filter->included_dialog_ids.push_back(get_input_dialog_id(dialog_id));
19027     }
19028 
19029     TRY_STATUS(new_dialog_filter->check_limits());
19030     sort_dialog_filter_input_dialog_ids(new_dialog_filter.get(), "toggle_dialog_is_pinned");
19031 
19032     edit_dialog_filter(std::move(new_dialog_filter), "toggle_dialog_is_pinned");
19033     save_dialog_filters();
19034     send_update_chat_filters();
19035 
19036     if (dialog_id.get_type() != DialogType::SecretChat) {
19037       synchronize_dialog_filters();
19038     }
19039 
19040     return Status::OK();
19041   }
19042 
19043   CHECK(dialog_list_id.is_folder());
19044   auto folder_id = dialog_list_id.get_folder_id();
19045   if (is_pinned) {
19046     if (d->folder_id != folder_id) {
19047       return Status::Error(400, "Chat not in the list");
19048     }
19049 
19050     auto pinned_dialog_ids = get_pinned_dialog_ids(dialog_list_id);
19051     auto pinned_dialog_count = pinned_dialog_ids.size();
19052     auto secret_pinned_dialog_count =
19053         std::count_if(pinned_dialog_ids.begin(), pinned_dialog_ids.end(),
19054                       [](DialogId dialog_id) { return dialog_id.get_type() == DialogType::SecretChat; });
19055     size_t dialog_count = dialog_id.get_type() == DialogType::SecretChat
19056                               ? secret_pinned_dialog_count
19057                               : pinned_dialog_count - secret_pinned_dialog_count;
19058 
19059     if (dialog_count >= static_cast<size_t>(get_pinned_dialogs_limit(dialog_list_id))) {
19060       return Status::Error(400, "The maximum number of pinned chats exceeded");
19061     }
19062   }
19063 
19064   if (set_dialog_is_pinned(dialog_list_id, d, is_pinned)) {
19065     toggle_dialog_is_pinned_on_server(dialog_id, is_pinned, 0);
19066   }
19067   return Status::OK();
19068 }
19069 
19070 class MessagesManager::ToggleDialogIsPinnedOnServerLogEvent {
19071  public:
19072   DialogId dialog_id_;
19073   bool is_pinned_;
19074 
19075   template <class StorerT>
store(StorerT & storer) const19076   void store(StorerT &storer) const {
19077     BEGIN_STORE_FLAGS();
19078     STORE_FLAG(is_pinned_);
19079     END_STORE_FLAGS();
19080 
19081     td::store(dialog_id_, storer);
19082   }
19083 
19084   template <class ParserT>
parse(ParserT & parser)19085   void parse(ParserT &parser) {
19086     BEGIN_PARSE_FLAGS();
19087     PARSE_FLAG(is_pinned_);
19088     END_PARSE_FLAGS();
19089 
19090     td::parse(dialog_id_, parser);
19091   }
19092 };
19093 
save_toggle_dialog_is_pinned_on_server_log_event(DialogId dialog_id,bool is_pinned)19094 uint64 MessagesManager::save_toggle_dialog_is_pinned_on_server_log_event(DialogId dialog_id, bool is_pinned) {
19095   ToggleDialogIsPinnedOnServerLogEvent log_event{dialog_id, is_pinned};
19096   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::ToggleDialogIsPinnedOnServer,
19097                     get_log_event_storer(log_event));
19098 }
19099 
toggle_dialog_is_pinned_on_server(DialogId dialog_id,bool is_pinned,uint64 log_event_id)19100 void MessagesManager::toggle_dialog_is_pinned_on_server(DialogId dialog_id, bool is_pinned, uint64 log_event_id) {
19101   CHECK(!td_->auth_manager_->is_bot());
19102   if (log_event_id == 0 && dialog_id.get_type() == DialogType::SecretChat) {
19103     // don't even create new binlog events
19104     return;
19105   }
19106 
19107   if (log_event_id == 0 && G()->parameters().use_message_db) {
19108     log_event_id = save_toggle_dialog_is_pinned_on_server_log_event(dialog_id, is_pinned);
19109   }
19110 
19111   td_->create_handler<ToggleDialogPinQuery>(get_erase_log_event_promise(log_event_id))->send(dialog_id, is_pinned);
19112 }
19113 
set_pinned_dialogs(DialogListId dialog_list_id,vector<DialogId> dialog_ids)19114 Status MessagesManager::set_pinned_dialogs(DialogListId dialog_list_id, vector<DialogId> dialog_ids) {
19115   if (td_->auth_manager_->is_bot()) {
19116     return Status::Error(400, "Bots can't reorder pinned chats");
19117   }
19118 
19119   int32 dialog_count = 0;
19120   int32 secret_dialog_count = 0;
19121   auto dialog_count_limit = get_pinned_dialogs_limit(dialog_list_id);
19122   for (auto dialog_id : dialog_ids) {
19123     Dialog *d = get_dialog_force(dialog_id, "set_pinned_dialogs");
19124     if (d == nullptr) {
19125       return Status::Error(400, "Chat not found");
19126     }
19127     if (!have_input_peer(dialog_id, AccessRights::Read)) {
19128       return Status::Error(400, "Can't access the chat");
19129     }
19130     if (d->order == DEFAULT_ORDER) {
19131       return Status::Error(400, "The chat can't be pinned");
19132     }
19133     if (dialog_list_id.is_folder() && d->folder_id != dialog_list_id.get_folder_id()) {
19134       return Status::Error(400, "Chat not in the list");
19135     }
19136     if (dialog_id.get_type() == DialogType::SecretChat) {
19137       secret_dialog_count++;
19138     } else {
19139       dialog_count++;
19140     }
19141 
19142     if (dialog_count > dialog_count_limit || secret_dialog_count > dialog_count_limit) {
19143       return Status::Error(400, "The maximum number of pinned chats exceeded");
19144     }
19145   }
19146   std::unordered_set<DialogId, DialogIdHash> new_pinned_dialog_ids(dialog_ids.begin(), dialog_ids.end());
19147   if (new_pinned_dialog_ids.size() != dialog_ids.size()) {
19148     return Status::Error(400, "Duplicate chats in the list of pinned chats");
19149   }
19150 
19151   auto *list = get_dialog_list(dialog_list_id);
19152   if (list == nullptr) {
19153     return Status::Error(400, "Chat list not found");
19154   }
19155   if (!list->are_pinned_dialogs_inited_) {
19156     return Status::Error(400, "Pinned chats must be loaded first");
19157   }
19158 
19159   auto pinned_dialog_ids = get_pinned_dialog_ids(dialog_list_id);
19160   if (pinned_dialog_ids == dialog_ids) {
19161     return Status::OK();
19162   }
19163   LOG(INFO) << "Reorder pinned chats in " << dialog_list_id << " from " << pinned_dialog_ids << " to " << dialog_ids;
19164 
19165   auto server_old_dialog_ids = remove_secret_chat_dialog_ids(pinned_dialog_ids);
19166   auto server_new_dialog_ids = remove_secret_chat_dialog_ids(dialog_ids);
19167 
19168   if (dialog_list_id.is_filter()) {
19169     CHECK(is_update_chat_filters_sent_);
19170     auto dialog_filter_id = dialog_list_id.get_filter_id();
19171     auto old_dialog_filter = get_dialog_filter(dialog_filter_id);
19172     CHECK(old_dialog_filter != nullptr);
19173     auto new_dialog_filter = make_unique<DialogFilter>(*old_dialog_filter);
19174     auto old_pinned_dialog_ids = std::move(new_dialog_filter->pinned_dialog_ids);
19175     new_dialog_filter->pinned_dialog_ids =
19176         transform(dialog_ids, [this](DialogId dialog_id) { return get_input_dialog_id(dialog_id); });
19177     auto is_new_pinned = [&new_pinned_dialog_ids](InputDialogId input_dialog_id) {
19178       return new_pinned_dialog_ids.count(input_dialog_id.get_dialog_id()) > 0;
19179     };
19180     td::remove_if(old_pinned_dialog_ids, is_new_pinned);
19181     td::remove_if(new_dialog_filter->included_dialog_ids, is_new_pinned);
19182     td::remove_if(new_dialog_filter->excluded_dialog_ids, is_new_pinned);
19183     append(new_dialog_filter->included_dialog_ids, old_pinned_dialog_ids);
19184 
19185     TRY_STATUS(new_dialog_filter->check_limits());
19186     sort_dialog_filter_input_dialog_ids(new_dialog_filter.get(), "set_pinned_dialogs");
19187 
19188     edit_dialog_filter(std::move(new_dialog_filter), "set_pinned_dialogs");
19189     save_dialog_filters();
19190     send_update_chat_filters();
19191 
19192     if (server_old_dialog_ids != server_new_dialog_ids) {
19193       synchronize_dialog_filters();
19194     }
19195 
19196     return Status::OK();
19197   }
19198 
19199   CHECK(dialog_list_id.is_folder());
19200 
19201   std::reverse(pinned_dialog_ids.begin(), pinned_dialog_ids.end());
19202   std::reverse(dialog_ids.begin(), dialog_ids.end());
19203 
19204   std::unordered_set<DialogId, DialogIdHash> old_pinned_dialog_ids(pinned_dialog_ids.begin(), pinned_dialog_ids.end());
19205   auto old_it = pinned_dialog_ids.begin();
19206   for (auto dialog_id : dialog_ids) {
19207     old_pinned_dialog_ids.erase(dialog_id);
19208     while (old_it < pinned_dialog_ids.end()) {
19209       if (*old_it == dialog_id) {
19210         break;
19211       }
19212       ++old_it;
19213     }
19214     if (old_it < pinned_dialog_ids.end()) {
19215       // leave dialog where it is
19216       ++old_it;
19217       continue;
19218     }
19219     set_dialog_is_pinned(dialog_id, true);
19220   }
19221   for (auto dialog_id : old_pinned_dialog_ids) {
19222     Dialog *d = get_dialog_force(dialog_id, "set_pinned_dialogs 2");
19223     if (d == nullptr) {
19224       LOG(ERROR) << "Failed to find " << dialog_id << " to unpin in " << dialog_list_id;
19225       force_create_dialog(dialog_id, "set_pinned_dialogs", true);
19226       d = get_dialog_force(dialog_id, "set_pinned_dialogs 3");
19227     }
19228     if (d != nullptr) {
19229       set_dialog_is_pinned(dialog_list_id, d, false);
19230     }
19231   }
19232 
19233   if (server_old_dialog_ids != server_new_dialog_ids) {
19234     reorder_pinned_dialogs_on_server(dialog_list_id.get_folder_id(), server_new_dialog_ids, 0);
19235   }
19236   return Status::OK();
19237 }
19238 
19239 class MessagesManager::ReorderPinnedDialogsOnServerLogEvent {
19240  public:
19241   FolderId folder_id_;
19242   vector<DialogId> dialog_ids_;
19243 
19244   template <class StorerT>
store(StorerT & storer) const19245   void store(StorerT &storer) const {
19246     td::store(folder_id_, storer);
19247     td::store(dialog_ids_, storer);
19248   }
19249 
19250   template <class ParserT>
parse(ParserT & parser)19251   void parse(ParserT &parser) {
19252     if (parser.version() >= static_cast<int32>(Version::AddFolders)) {
19253       td::parse(folder_id_, parser);
19254     } else {
19255       folder_id_ = FolderId();
19256     }
19257     td::parse(dialog_ids_, parser);
19258   }
19259 };
19260 
save_reorder_pinned_dialogs_on_server_log_event(FolderId folder_id,const vector<DialogId> & dialog_ids)19261 uint64 MessagesManager::save_reorder_pinned_dialogs_on_server_log_event(FolderId folder_id,
19262                                                                         const vector<DialogId> &dialog_ids) {
19263   ReorderPinnedDialogsOnServerLogEvent log_event{folder_id, dialog_ids};
19264   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::ReorderPinnedDialogsOnServer,
19265                     get_log_event_storer(log_event));
19266 }
19267 
reorder_pinned_dialogs_on_server(FolderId folder_id,const vector<DialogId> & dialog_ids,uint64 log_event_id)19268 void MessagesManager::reorder_pinned_dialogs_on_server(FolderId folder_id, const vector<DialogId> &dialog_ids,
19269                                                        uint64 log_event_id) {
19270   if (log_event_id == 0 && G()->parameters().use_message_db) {
19271     log_event_id = save_reorder_pinned_dialogs_on_server_log_event(folder_id, dialog_ids);
19272   }
19273 
19274   td_->create_handler<ReorderPinnedDialogsQuery>(get_erase_log_event_promise(log_event_id))
19275       ->send(folder_id, dialog_ids);
19276 }
19277 
toggle_dialog_is_marked_as_unread(DialogId dialog_id,bool is_marked_as_unread)19278 Status MessagesManager::toggle_dialog_is_marked_as_unread(DialogId dialog_id, bool is_marked_as_unread) {
19279   Dialog *d = get_dialog_force(dialog_id, "toggle_dialog_is_marked_as_unread");
19280   if (d == nullptr) {
19281     return Status::Error(400, "Chat not found");
19282   }
19283   if (!have_input_peer(dialog_id, AccessRights::Read)) {
19284     return Status::Error(400, "Can't access the chat");
19285   }
19286 
19287   if (is_marked_as_unread == d->is_marked_as_unread) {
19288     return Status::OK();
19289   }
19290 
19291   set_dialog_is_marked_as_unread(d, is_marked_as_unread);
19292 
19293   toggle_dialog_is_marked_as_unread_on_server(dialog_id, is_marked_as_unread, 0);
19294   return Status::OK();
19295 }
19296 
19297 class MessagesManager::ToggleDialogIsMarkedAsUnreadOnServerLogEvent {
19298  public:
19299   DialogId dialog_id_;
19300   bool is_marked_as_unread_;
19301 
19302   template <class StorerT>
store(StorerT & storer) const19303   void store(StorerT &storer) const {
19304     BEGIN_STORE_FLAGS();
19305     STORE_FLAG(is_marked_as_unread_);
19306     END_STORE_FLAGS();
19307 
19308     td::store(dialog_id_, storer);
19309   }
19310 
19311   template <class ParserT>
parse(ParserT & parser)19312   void parse(ParserT &parser) {
19313     BEGIN_PARSE_FLAGS();
19314     PARSE_FLAG(is_marked_as_unread_);
19315     END_PARSE_FLAGS();
19316 
19317     td::parse(dialog_id_, parser);
19318   }
19319 };
19320 
save_toggle_dialog_is_marked_as_unread_on_server_log_event(DialogId dialog_id,bool is_marked_as_unread)19321 uint64 MessagesManager::save_toggle_dialog_is_marked_as_unread_on_server_log_event(DialogId dialog_id,
19322                                                                                    bool is_marked_as_unread) {
19323   ToggleDialogIsMarkedAsUnreadOnServerLogEvent log_event{dialog_id, is_marked_as_unread};
19324   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::ToggleDialogIsMarkedAsUnreadOnServer,
19325                     get_log_event_storer(log_event));
19326 }
19327 
toggle_dialog_is_marked_as_unread_on_server(DialogId dialog_id,bool is_marked_as_unread,uint64 log_event_id)19328 void MessagesManager::toggle_dialog_is_marked_as_unread_on_server(DialogId dialog_id, bool is_marked_as_unread,
19329                                                                   uint64 log_event_id) {
19330   if (log_event_id == 0 && dialog_id.get_type() == DialogType::SecretChat) {
19331     // don't even create new binlog events
19332     return;
19333   }
19334 
19335   if (log_event_id == 0 && G()->parameters().use_message_db) {
19336     log_event_id = save_toggle_dialog_is_marked_as_unread_on_server_log_event(dialog_id, is_marked_as_unread);
19337   }
19338 
19339   td_->create_handler<ToggleDialogUnreadMarkQuery>(get_erase_log_event_promise(log_event_id))
19340       ->send(dialog_id, is_marked_as_unread);
19341 }
19342 
toggle_message_sender_is_blocked(const td_api::object_ptr<td_api::MessageSender> & sender,bool is_blocked)19343 Status MessagesManager::toggle_message_sender_is_blocked(const td_api::object_ptr<td_api::MessageSender> &sender,
19344                                                          bool is_blocked) {
19345   TRY_RESULT(dialog_id, get_message_sender_dialog_id(td_, sender, true, false));
19346   switch (dialog_id.get_type()) {
19347     case DialogType::User:
19348       if (dialog_id == get_my_dialog_id()) {
19349         return Status::Error(400, is_blocked ? Slice("Can't block self") : Slice("Can't unblock self"));
19350       }
19351       break;
19352     case DialogType::Chat:
19353       return Status::Error(400, "Basic group chats can't be blocked");
19354     case DialogType::Channel:
19355       // ok
19356       break;
19357     case DialogType::SecretChat: {
19358       auto user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id());
19359       if (!user_id.is_valid() || !td_->contacts_manager_->have_user_force(user_id)) {
19360         return Status::Error(400, "The secret chat can't be blocked");
19361       }
19362       dialog_id = DialogId(user_id);
19363       break;
19364     }
19365     case DialogType::None:
19366     default:
19367       UNREACHABLE();
19368   }
19369 
19370   Dialog *d = get_dialog_force(dialog_id, "toggle_message_sender_is_blocked");
19371   if (!have_input_peer(dialog_id, AccessRights::Know)) {
19372     return Status::Error(400, "Message sender isn't accessible");
19373   }
19374   if (d != nullptr) {
19375     if (is_blocked == d->is_blocked) {
19376       return Status::OK();
19377     }
19378     set_dialog_is_blocked(d, is_blocked);
19379   } else {
19380     CHECK(dialog_id.get_type() == DialogType::User);
19381     td_->contacts_manager_->on_update_user_is_blocked(dialog_id.get_user_id(), is_blocked);
19382   }
19383 
19384   toggle_dialog_is_blocked_on_server(dialog_id, is_blocked, 0);
19385   return Status::OK();
19386 }
19387 
19388 class MessagesManager::ToggleDialogIsBlockedOnServerLogEvent {
19389  public:
19390   DialogId dialog_id_;
19391   bool is_blocked_;
19392 
19393   template <class StorerT>
store(StorerT & storer) const19394   void store(StorerT &storer) const {
19395     BEGIN_STORE_FLAGS();
19396     STORE_FLAG(is_blocked_);
19397     END_STORE_FLAGS();
19398 
19399     td::store(dialog_id_, storer);
19400   }
19401 
19402   template <class ParserT>
parse(ParserT & parser)19403   void parse(ParserT &parser) {
19404     BEGIN_PARSE_FLAGS();
19405     PARSE_FLAG(is_blocked_);
19406     END_PARSE_FLAGS();
19407 
19408     td::parse(dialog_id_, parser);
19409   }
19410 };
19411 
save_toggle_dialog_is_blocked_on_server_log_event(DialogId dialog_id,bool is_blocked)19412 uint64 MessagesManager::save_toggle_dialog_is_blocked_on_server_log_event(DialogId dialog_id, bool is_blocked) {
19413   ToggleDialogIsBlockedOnServerLogEvent log_event{dialog_id, is_blocked};
19414   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::ToggleDialogIsBlockedOnServer,
19415                     get_log_event_storer(log_event));
19416 }
19417 
toggle_dialog_is_blocked_on_server(DialogId dialog_id,bool is_blocked,uint64 log_event_id)19418 void MessagesManager::toggle_dialog_is_blocked_on_server(DialogId dialog_id, bool is_blocked, uint64 log_event_id) {
19419   if (log_event_id == 0 && G()->parameters().use_message_db) {
19420     log_event_id = save_toggle_dialog_is_blocked_on_server_log_event(dialog_id, is_blocked);
19421   }
19422 
19423   send_closure(td_->create_net_actor<ToggleDialogIsBlockedActor>(get_erase_log_event_promise(log_event_id)),
19424                &ToggleDialogIsBlockedActor::send, dialog_id, is_blocked,
19425                get_sequence_dispatcher_id(dialog_id, MessageContentType::Text));
19426 }
19427 
toggle_dialog_silent_send_message(DialogId dialog_id,bool silent_send_message)19428 Status MessagesManager::toggle_dialog_silent_send_message(DialogId dialog_id, bool silent_send_message) {
19429   CHECK(!td_->auth_manager_->is_bot());
19430 
19431   Dialog *d = get_dialog_force(dialog_id, "toggle_dialog_silent_send_message");
19432   if (d == nullptr) {
19433     return Status::Error(400, "Chat not found");
19434   }
19435   if (!have_input_peer(dialog_id, AccessRights::Read)) {
19436     return Status::Error(400, "Can't access the chat");
19437   }
19438 
19439   if (update_dialog_silent_send_message(d, silent_send_message)) {
19440     update_dialog_notification_settings_on_server(dialog_id, false);
19441   }
19442 
19443   return Status::OK();
19444 }
19445 
19446 class MessagesManager::UpdateDialogNotificationSettingsOnServerLogEvent {
19447  public:
19448   DialogId dialog_id_;
19449 
19450   template <class StorerT>
store(StorerT & storer) const19451   void store(StorerT &storer) const {
19452     td::store(dialog_id_, storer);
19453   }
19454 
19455   template <class ParserT>
parse(ParserT & parser)19456   void parse(ParserT &parser) {
19457     td::parse(dialog_id_, parser);
19458   }
19459 };
19460 
update_dialog_notification_settings_on_server(DialogId dialog_id,bool from_binlog)19461 void MessagesManager::update_dialog_notification_settings_on_server(DialogId dialog_id, bool from_binlog) {
19462   if (td_->auth_manager_->is_bot()) {
19463     // just in case
19464     return;
19465   }
19466 
19467   if (!from_binlog && get_input_notify_peer(dialog_id) == nullptr) {
19468     // don't even create new binlog events
19469     return;
19470   }
19471 
19472   auto d = get_dialog(dialog_id);
19473   CHECK(d != nullptr);
19474 
19475   if (!from_binlog && G()->parameters().use_message_db) {
19476     UpdateDialogNotificationSettingsOnServerLogEvent log_event;
19477     log_event.dialog_id_ = dialog_id;
19478     add_log_event(d->save_notification_settings_log_event_id, get_log_event_storer(log_event),
19479                   LogEvent::HandlerType::UpdateDialogNotificationSettingsOnServer, "notification settings");
19480   }
19481 
19482   Promise<> promise;
19483   if (d->save_notification_settings_log_event_id.log_event_id != 0) {
19484     d->save_notification_settings_log_event_id.generation++;
19485     promise = PromiseCreator::lambda(
19486         [actor_id = actor_id(this), dialog_id,
19487          generation = d->save_notification_settings_log_event_id.generation](Result<Unit> result) {
19488           if (!G()->close_flag()) {
19489             send_closure(actor_id, &MessagesManager::on_updated_dialog_notification_settings, dialog_id, generation);
19490           }
19491         });
19492   }
19493 
19494   send_update_dialog_notification_settings_query(d, std::move(promise));
19495 }
19496 
send_update_dialog_notification_settings_query(const Dialog * d,Promise<Unit> && promise)19497 void MessagesManager::send_update_dialog_notification_settings_query(const Dialog *d, Promise<Unit> &&promise) {
19498   CHECK(!td_->auth_manager_->is_bot());
19499   CHECK(d != nullptr);
19500   // TODO do not send two queries simultaneously or use SequenceDispatcher
19501   td_->create_handler<UpdateDialogNotifySettingsQuery>(std::move(promise))
19502       ->send(d->dialog_id, d->notification_settings);
19503 }
19504 
on_updated_dialog_notification_settings(DialogId dialog_id,uint64 generation)19505 void MessagesManager::on_updated_dialog_notification_settings(DialogId dialog_id, uint64 generation) {
19506   CHECK(!td_->auth_manager_->is_bot());
19507   auto d = get_dialog(dialog_id);
19508   CHECK(d != nullptr);
19509   delete_log_event(d->save_notification_settings_log_event_id, generation, "notification settings");
19510 }
19511 
set_dialog_client_data(DialogId dialog_id,string && client_data)19512 Status MessagesManager::set_dialog_client_data(DialogId dialog_id, string &&client_data) {
19513   Dialog *d = get_dialog_force(dialog_id, "set_dialog_client_data");
19514   if (d == nullptr) {
19515     return Status::Error(400, "Chat not found");
19516   }
19517 
19518   d->client_data = std::move(client_data);
19519   on_dialog_updated(d->dialog_id, "set_dialog_client_data");
19520   return Status::OK();
19521 }
19522 
is_dialog_inited(const Dialog * d)19523 bool MessagesManager::is_dialog_inited(const Dialog *d) {
19524   return d != nullptr && d->notification_settings.is_synchronized && d->is_last_read_inbox_message_id_inited &&
19525          d->is_last_read_outbox_message_id_inited;
19526 }
19527 
get_dialog_mute_until(const Dialog * d) const19528 int32 MessagesManager::get_dialog_mute_until(const Dialog *d) const {
19529   CHECK(!td_->auth_manager_->is_bot());
19530   CHECK(d != nullptr);
19531   return d->notification_settings.use_default_mute_until ? get_scope_mute_until(d->dialog_id)
19532                                                          : d->notification_settings.mute_until;
19533 }
19534 
is_dialog_muted(const Dialog * d) const19535 bool MessagesManager::is_dialog_muted(const Dialog *d) const {
19536   return get_dialog_mute_until(d) != 0;
19537 }
19538 
is_dialog_pinned_message_notifications_disabled(const Dialog * d) const19539 bool MessagesManager::is_dialog_pinned_message_notifications_disabled(const Dialog *d) const {
19540   CHECK(!td_->auth_manager_->is_bot());
19541   CHECK(d != nullptr);
19542   if (d->notification_settings.use_default_disable_pinned_message_notifications) {
19543     auto scope = get_dialog_notification_setting_scope(d->dialog_id);
19544     return get_scope_notification_settings(scope)->disable_pinned_message_notifications;
19545   }
19546 
19547   return d->notification_settings.disable_pinned_message_notifications;
19548 }
19549 
is_dialog_mention_notifications_disabled(const Dialog * d) const19550 bool MessagesManager::is_dialog_mention_notifications_disabled(const Dialog *d) const {
19551   CHECK(!td_->auth_manager_->is_bot());
19552   CHECK(d != nullptr);
19553   if (d->notification_settings.use_default_disable_mention_notifications) {
19554     auto scope = get_dialog_notification_setting_scope(d->dialog_id);
19555     return get_scope_notification_settings(scope)->disable_mention_notifications;
19556   }
19557 
19558   return d->notification_settings.disable_mention_notifications;
19559 }
19560 
create_dialog(DialogId dialog_id,bool force,Promise<Unit> && promise)19561 void MessagesManager::create_dialog(DialogId dialog_id, bool force, Promise<Unit> &&promise) {
19562   if (!have_input_peer(dialog_id, AccessRights::Read)) {
19563     if (!have_dialog_info_force(dialog_id)) {
19564       return promise.set_error(Status::Error(400, "Chat info not found"));
19565     }
19566     if (!have_input_peer(dialog_id, AccessRights::Read)) {
19567       return promise.set_error(Status::Error(400, "Can't access the chat"));
19568     }
19569   }
19570 
19571   if (force || td_->auth_manager_->is_bot() || dialog_id.get_type() == DialogType::SecretChat) {
19572     force_create_dialog(dialog_id, "create dialog");
19573   } else {
19574     const Dialog *d = get_dialog_force(dialog_id, "create_dialog");
19575     if (!is_dialog_inited(d)) {
19576       return send_get_dialog_query(dialog_id, std::move(promise), 0, "create_dialog");
19577     }
19578   }
19579 
19580   promise.set_value(Unit());
19581 }
19582 
create_new_group_chat(const vector<UserId> & user_ids,const string & title,int64 & random_id,Promise<Unit> && promise)19583 DialogId MessagesManager::create_new_group_chat(const vector<UserId> &user_ids, const string &title, int64 &random_id,
19584                                                 Promise<Unit> &&promise) {
19585   LOG(INFO) << "Trying to create group chat \"" << title << "\" with members " << format::as_array(user_ids);
19586 
19587   if (random_id != 0) {
19588     // request has already been sent before
19589     auto it = created_dialogs_.find(random_id);
19590     CHECK(it != created_dialogs_.end());
19591     auto dialog_id = it->second;
19592     CHECK(dialog_id.get_type() == DialogType::Chat);
19593     CHECK(have_dialog(dialog_id));
19594 
19595     created_dialogs_.erase(it);
19596 
19597     // set default notification settings to newly created chat
19598     on_update_dialog_notify_settings(dialog_id, make_tl_object<telegram_api::peerNotifySettings>(),
19599                                      "create_new_group_chat");
19600 
19601     promise.set_value(Unit());
19602     return dialog_id;
19603   }
19604 
19605   if (user_ids.empty()) {
19606     promise.set_error(Status::Error(400, "Too few users to create basic group chat"));
19607     return DialogId();
19608   }
19609 
19610   auto new_title = clean_name(title, MAX_TITLE_LENGTH);
19611   if (new_title.empty()) {
19612     promise.set_error(Status::Error(400, "Title can't be empty"));
19613     return DialogId();
19614   }
19615 
19616   vector<tl_object_ptr<telegram_api::InputUser>> input_users;
19617   for (auto user_id : user_ids) {
19618     auto input_user = td_->contacts_manager_->get_input_user(user_id);
19619     if (input_user == nullptr) {
19620       promise.set_error(Status::Error(400, "User not found"));
19621       return DialogId();
19622     }
19623     input_users.push_back(std::move(input_user));
19624   }
19625 
19626   do {
19627     random_id = Random::secure_int64();
19628   } while (random_id == 0 || created_dialogs_.find(random_id) != created_dialogs_.end());
19629   created_dialogs_[random_id];  // reserve place for result
19630 
19631   td_->create_handler<CreateChatQuery>(std::move(promise))->send(std::move(input_users), new_title, random_id);
19632   return DialogId();
19633 }
19634 
create_new_channel_chat(const string & title,bool is_megagroup,const string & description,const DialogLocation & location,bool for_import,int64 & random_id,Promise<Unit> && promise)19635 DialogId MessagesManager::create_new_channel_chat(const string &title, bool is_megagroup, const string &description,
19636                                                   const DialogLocation &location, bool for_import, int64 &random_id,
19637                                                   Promise<Unit> &&promise) {
19638   LOG(INFO) << "Trying to create " << (is_megagroup ? "supergroup" : "broadcast") << " with title \"" << title
19639             << "\", description \"" << description << "\" and " << location;
19640 
19641   if (random_id != 0) {
19642     // request has already been sent before
19643     auto it = created_dialogs_.find(random_id);
19644     CHECK(it != created_dialogs_.end());
19645     auto dialog_id = it->second;
19646     CHECK(dialog_id.get_type() == DialogType::Channel);
19647     CHECK(have_dialog(dialog_id));
19648 
19649     created_dialogs_.erase(it);
19650 
19651     // set default notification settings to newly created chat
19652     on_update_dialog_notify_settings(dialog_id, make_tl_object<telegram_api::peerNotifySettings>(),
19653                                      "create_new_channel_chat");
19654 
19655     promise.set_value(Unit());
19656     return dialog_id;
19657   }
19658 
19659   auto new_title = clean_name(title, MAX_TITLE_LENGTH);
19660   if (new_title.empty()) {
19661     promise.set_error(Status::Error(400, "Title can't be empty"));
19662     return DialogId();
19663   }
19664 
19665   do {
19666     random_id = Random::secure_int64();
19667   } while (random_id == 0 || created_dialogs_.find(random_id) != created_dialogs_.end());
19668   created_dialogs_[random_id];  // reserve place for result
19669 
19670   td_->create_handler<CreateChannelQuery>(std::move(promise))
19671       ->send(new_title, is_megagroup, strip_empty_characters(description, MAX_DESCRIPTION_LENGTH), location, for_import,
19672              random_id);
19673   return DialogId();
19674 }
19675 
create_new_secret_chat(UserId user_id,Promise<SecretChatId> && promise)19676 void MessagesManager::create_new_secret_chat(UserId user_id, Promise<SecretChatId> &&promise) {
19677   auto user_base = td_->contacts_manager_->get_input_user(user_id);
19678   if (user_base == nullptr || user_base->get_id() != telegram_api::inputUser::ID) {
19679     return promise.set_error(Status::Error(400, "User not found"));
19680   }
19681   auto user = move_tl_object_as<telegram_api::inputUser>(user_base);
19682 
19683   send_closure(G()->secret_chats_manager(), &SecretChatsManager::create_chat, UserId(user->user_id_),
19684                user->access_hash_, std::move(promise));
19685 }
19686 
migrate_dialog_to_megagroup(DialogId dialog_id,Promise<Unit> && promise)19687 DialogId MessagesManager::migrate_dialog_to_megagroup(DialogId dialog_id, Promise<Unit> &&promise) {
19688   LOG(INFO) << "Trying to convert " << dialog_id << " to supergroup";
19689 
19690   if (dialog_id.get_type() != DialogType::Chat) {
19691     promise.set_error(Status::Error(400, "Only basic group chats can be converted to supergroup"));
19692     return DialogId();
19693   }
19694 
19695   auto channel_id = td_->contacts_manager_->migrate_chat_to_megagroup(dialog_id.get_chat_id(), promise);
19696   if (!channel_id.is_valid()) {
19697     return DialogId();
19698   }
19699 
19700   if (!td_->contacts_manager_->have_channel(channel_id)) {
19701     LOG(ERROR) << "Can't find info about supergroup to which the group has migrated";
19702     promise.set_error(Status::Error(400, "Supergroup is not found"));
19703     return DialogId();
19704   }
19705 
19706   auto new_dialog_id = DialogId(channel_id);
19707   Dialog *d = get_dialog_force(new_dialog_id, "migrate_dialog_to_megagroup");
19708   if (d == nullptr) {
19709     d = add_dialog(new_dialog_id, "migrate_dialog_to_megagroup");
19710     if (d->pts == 0) {
19711       d->pts = 1;
19712       if (is_debug_message_op_enabled()) {
19713         d->debug_message_op.emplace_back(Dialog::MessageOp::SetPts, d->pts, "migrate");
19714       }
19715     }
19716     update_dialog_pos(d, "migrate_dialog_to_megagroup");
19717   }
19718 
19719   promise.set_value(Unit());
19720   return new_dialog_id;
19721 }
19722 
is_dialog_opened(DialogId dialog_id) const19723 bool MessagesManager::is_dialog_opened(DialogId dialog_id) const {
19724   const Dialog *d = get_dialog(dialog_id);
19725   return d != nullptr && d->is_opened;
19726 }
19727 
open_dialog(DialogId dialog_id)19728 Status MessagesManager::open_dialog(DialogId dialog_id) {
19729   Dialog *d = get_dialog_force(dialog_id, "open_dialog");
19730   if (d == nullptr) {
19731     return Status::Error(400, "Chat not found");
19732   }
19733 
19734   open_dialog(d);
19735   return Status::OK();
19736 }
19737 
close_dialog(DialogId dialog_id)19738 Status MessagesManager::close_dialog(DialogId dialog_id) {
19739   Dialog *d = get_dialog_force(dialog_id, "close_dialog");
19740   if (d == nullptr) {
19741     return Status::Error(400, "Chat not found");
19742   }
19743 
19744   close_dialog(d);
19745   return Status::OK();
19746 }
19747 
get_my_dialog_id() const19748 DialogId MessagesManager::get_my_dialog_id() const {
19749   return DialogId(td_->contacts_manager_->get_my_id());
19750 }
19751 
view_messages(DialogId dialog_id,MessageId top_thread_message_id,const vector<MessageId> & message_ids,bool force_read)19752 Status MessagesManager::view_messages(DialogId dialog_id, MessageId top_thread_message_id,
19753                                       const vector<MessageId> &message_ids, bool force_read) {
19754   CHECK(!td_->auth_manager_->is_bot());
19755 
19756   Dialog *d = get_dialog_force(dialog_id, "view_messages");
19757   if (d == nullptr) {
19758     return Status::Error(400, "Chat not found");
19759   }
19760   for (auto message_id : message_ids) {
19761     if (!message_id.is_valid() && !message_id.is_valid_scheduled()) {
19762       return Status::Error(400, "Invalid message identifier");
19763     }
19764   }
19765   if (!have_input_peer(dialog_id, AccessRights::Read)) {
19766     return Status::Error(400, "Can't access the chat");
19767   }
19768 
19769   if (top_thread_message_id != MessageId()) {
19770     if (!top_thread_message_id.is_valid() || !top_thread_message_id.is_server()) {
19771       return Status::Error(400, "Invalid message thread ID specified");
19772     }
19773     if (dialog_id.get_type() != DialogType::Channel || is_broadcast_channel(dialog_id)) {
19774       return Status::Error(400, "There are no message threads in the chat");
19775     }
19776   }
19777 
19778   bool need_read = force_read || d->is_opened;
19779   MessageId max_message_id;  // max server or local viewed message_id
19780   vector<MessageId> read_content_message_ids;
19781   for (auto message_id : message_ids) {
19782     if (!message_id.is_valid()) {
19783       continue;
19784     }
19785 
19786     auto *m = get_message_force(d, message_id, "view_messages");
19787     if (m != nullptr) {
19788       if (m->message_id.is_server() && m->view_count > 0) {
19789         d->pending_viewed_message_ids.insert(m->message_id);
19790       }
19791 
19792       if (!m->message_id.is_yet_unsent() && m->message_id > max_message_id) {
19793         max_message_id = m->message_id;
19794       }
19795 
19796       auto message_content_type = m->content->get_type();
19797       if (message_content_type == MessageContentType::LiveLocation) {
19798         on_message_live_location_viewed(d, m);
19799       }
19800 
19801       if (need_read && message_content_type != MessageContentType::VoiceNote &&
19802           message_content_type != MessageContentType::VideoNote &&
19803           update_message_contains_unread_mention(d, m, false, "view_messages")) {
19804         CHECK(m->message_id.is_server());
19805         read_content_message_ids.push_back(m->message_id);
19806         on_message_changed(d, m, true, "view_messages");
19807       }
19808     } else if (!message_id.is_yet_unsent() && message_id > max_message_id &&
19809                message_id <= d->max_notification_message_id) {
19810       max_message_id = message_id;
19811     }
19812   }
19813   if (!d->pending_viewed_message_ids.empty()) {
19814     pending_message_views_timeout_.add_timeout_in(dialog_id.get(), MAX_MESSAGE_VIEW_DELAY);
19815     d->increment_view_counter |= d->is_opened;
19816   }
19817   if (!read_content_message_ids.empty()) {
19818     read_message_contents_on_server(dialog_id, std::move(read_content_message_ids), 0, Auto());
19819   }
19820 
19821   if (!need_read) {
19822     return Status::OK();
19823   }
19824 
19825   if (top_thread_message_id.is_valid()) {
19826     MessageId prev_last_read_inbox_message_id;
19827     MessageId max_thread_message_id;
19828     Message *top_m = get_message_force(d, top_thread_message_id, "view_messages 2");
19829     if (top_m != nullptr && is_active_message_reply_info(dialog_id, top_m->reply_info)) {
19830       prev_last_read_inbox_message_id = top_m->reply_info.last_read_inbox_message_id;
19831       if (top_m->reply_info.update_max_message_ids(MessageId(), max_message_id, MessageId())) {
19832         on_message_reply_info_changed(dialog_id, top_m);
19833         on_message_changed(d, top_m, true, "view_messages 3");
19834       }
19835       max_thread_message_id = top_m->reply_info.max_message_id;
19836 
19837       if (is_discussion_message(dialog_id, top_m)) {
19838         auto linked_dialog_id = top_m->forward_info->from_dialog_id;
19839         auto linked_d = get_dialog(linked_dialog_id);
19840         CHECK(linked_d != nullptr);
19841         CHECK(linked_dialog_id.get_type() == DialogType::Channel);
19842         auto *linked_m = get_message_force(linked_d, top_m->forward_info->from_message_id, "view_messages 4");
19843         if (linked_m != nullptr && is_active_message_reply_info(linked_dialog_id, linked_m->reply_info)) {
19844           if (linked_m->reply_info.last_read_inbox_message_id < prev_last_read_inbox_message_id) {
19845             prev_last_read_inbox_message_id = linked_m->reply_info.last_read_inbox_message_id;
19846           }
19847           if (linked_m->reply_info.update_max_message_ids(MessageId(), max_message_id, MessageId())) {
19848             on_message_reply_info_changed(linked_dialog_id, linked_m);
19849             on_message_changed(linked_d, linked_m, true, "view_messages 5");
19850           }
19851           if (linked_m->reply_info.max_message_id > max_thread_message_id) {
19852             max_thread_message_id = linked_m->reply_info.max_message_id;
19853           }
19854         }
19855       }
19856     }
19857 
19858     if (max_message_id.get_prev_server_message_id().get() >
19859         prev_last_read_inbox_message_id.get_prev_server_message_id().get()) {
19860       read_message_thread_history_on_server(d, top_thread_message_id, max_message_id.get_prev_server_message_id(),
19861                                             max_thread_message_id.get_prev_server_message_id());
19862     }
19863 
19864     return Status::OK();
19865   }
19866 
19867   if (max_message_id > d->last_read_inbox_message_id) {
19868     const MessageId last_read_message_id = max_message_id;
19869     const MessageId prev_last_read_inbox_message_id = d->last_read_inbox_message_id;
19870     MessageId read_history_on_server_message_id;
19871     if (dialog_id.get_type() != DialogType::SecretChat) {
19872       if (last_read_message_id.get_prev_server_message_id().get() >
19873           prev_last_read_inbox_message_id.get_prev_server_message_id().get()) {
19874         read_history_on_server_message_id = last_read_message_id.get_prev_server_message_id();
19875       }
19876     } else {
19877       if (last_read_message_id > prev_last_read_inbox_message_id) {
19878         read_history_on_server_message_id = last_read_message_id;
19879       }
19880     }
19881 
19882     if (read_history_on_server_message_id.is_valid()) {
19883       // add dummy timeout to not try to repair unread_count in read_history_inbox before server request succeeds
19884       // the timeout will be overwritten in the read_history_on_server call
19885       pending_read_history_timeout_.add_timeout_in(dialog_id.get(), 0);
19886     }
19887     read_history_inbox(d->dialog_id, last_read_message_id, -1, "view_messages");
19888     if (read_history_on_server_message_id.is_valid()) {
19889       // call read_history_on_server after read_history_inbox to not have delay before request if all messages are read
19890       read_history_on_server(d, read_history_on_server_message_id);
19891     }
19892   }
19893   if (d->is_marked_as_unread) {
19894     set_dialog_is_marked_as_unread(d, false);
19895   }
19896 
19897   return Status::OK();
19898 }
19899 
open_message_content(FullMessageId full_message_id)19900 Status MessagesManager::open_message_content(FullMessageId full_message_id) {
19901   auto dialog_id = full_message_id.get_dialog_id();
19902   Dialog *d = get_dialog_force(dialog_id, "open_message_content");
19903   if (d == nullptr) {
19904     return Status::Error(400, "Chat not found");
19905   }
19906 
19907   auto *m = get_message_force(d, full_message_id.get_message_id(), "open_message_content");
19908   if (m == nullptr) {
19909     return Status::Error(400, "Message not found");
19910   }
19911 
19912   if (m->message_id.is_scheduled() || m->message_id.is_yet_unsent() || m->is_outgoing) {
19913     return Status::OK();
19914   }
19915 
19916   if (read_message_content(d, m, true, "open_message_content") &&
19917       (m->message_id.is_server() || dialog_id.get_type() == DialogType::SecretChat)) {
19918     read_message_contents_on_server(dialog_id, {m->message_id}, 0, Auto());
19919   }
19920 
19921   if (m->content->get_type() == MessageContentType::LiveLocation) {
19922     on_message_live_location_viewed(d, m);
19923   }
19924 
19925   return Status::OK();
19926 }
19927 
19928 class MessagesManager::ReadMessageContentsOnServerLogEvent {
19929  public:
19930   DialogId dialog_id_;
19931   vector<MessageId> message_ids_;
19932 
19933   template <class StorerT>
store(StorerT & storer) const19934   void store(StorerT &storer) const {
19935     td::store(dialog_id_, storer);
19936     td::store(message_ids_, storer);
19937   }
19938 
19939   template <class ParserT>
parse(ParserT & parser)19940   void parse(ParserT &parser) {
19941     td::parse(dialog_id_, parser);
19942     td::parse(message_ids_, parser);
19943   }
19944 };
19945 
save_read_message_contents_on_server_log_event(DialogId dialog_id,const vector<MessageId> & message_ids)19946 uint64 MessagesManager::save_read_message_contents_on_server_log_event(DialogId dialog_id,
19947                                                                        const vector<MessageId> &message_ids) {
19948   ReadMessageContentsOnServerLogEvent log_event{dialog_id, message_ids};
19949   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::ReadMessageContentsOnServer,
19950                     get_log_event_storer(log_event));
19951 }
19952 
read_message_contents_on_server(DialogId dialog_id,vector<MessageId> message_ids,uint64 log_event_id,Promise<Unit> && promise,bool skip_log_event)19953 void MessagesManager::read_message_contents_on_server(DialogId dialog_id, vector<MessageId> message_ids,
19954                                                       uint64 log_event_id, Promise<Unit> &&promise,
19955                                                       bool skip_log_event) {
19956   CHECK(!message_ids.empty());
19957 
19958   LOG(INFO) << "Read contents of " << format::as_array(message_ids) << " in " << dialog_id << " on server";
19959 
19960   if (log_event_id == 0 && G()->parameters().use_message_db && !skip_log_event) {
19961     log_event_id = save_read_message_contents_on_server_log_event(dialog_id, message_ids);
19962   }
19963 
19964   auto new_promise = get_erase_log_event_promise(log_event_id, std::move(promise));
19965   promise = std::move(new_promise);  // to prevent self-move
19966 
19967   switch (dialog_id.get_type()) {
19968     case DialogType::User:
19969     case DialogType::Chat:
19970       td_->create_handler<ReadMessagesContentsQuery>(std::move(promise))->send(std::move(message_ids));
19971       break;
19972     case DialogType::Channel:
19973       td_->create_handler<ReadChannelMessagesContentsQuery>(std::move(promise))
19974           ->send(dialog_id.get_channel_id(), std::move(message_ids));
19975       break;
19976     case DialogType::SecretChat: {
19977       CHECK(message_ids.size() == 1);
19978       auto m = get_message_force({dialog_id, message_ids[0]}, "read_message_contents_on_server");
19979       if (m != nullptr) {
19980         send_closure(G()->secret_chats_manager(), &SecretChatsManager::send_open_message,
19981                      dialog_id.get_secret_chat_id(), m->random_id, std::move(promise));
19982       } else {
19983         promise.set_error(Status::Error(400, "Message not found"));
19984       }
19985       break;
19986     }
19987     case DialogType::None:
19988     default:
19989       UNREACHABLE();
19990   }
19991 }
19992 
click_animated_emoji_message(FullMessageId full_message_id,Promise<td_api::object_ptr<td_api::sticker>> && promise)19993 void MessagesManager::click_animated_emoji_message(FullMessageId full_message_id,
19994                                                    Promise<td_api::object_ptr<td_api::sticker>> &&promise) {
19995   auto dialog_id = full_message_id.get_dialog_id();
19996   Dialog *d = get_dialog_force(dialog_id, "click_animated_emoji_message");
19997   if (d == nullptr) {
19998     return promise.set_error(Status::Error(400, "Chat not found"));
19999   }
20000 
20001   auto message_id = get_persistent_message_id(d, full_message_id.get_message_id());
20002   auto *m = get_message_force(d, message_id, "click_animated_emoji_message");
20003   if (m == nullptr) {
20004     return promise.set_error(Status::Error(400, "Message not found"));
20005   }
20006 
20007   if (m->message_id.is_scheduled() || dialog_id.get_type() != DialogType::User || !m->message_id.is_server()) {
20008     return promise.set_value(nullptr);
20009   }
20010 
20011   get_message_content_animated_emoji_click_sticker(m->content.get(), full_message_id, td_, std::move(promise));
20012 }
20013 
open_dialog(Dialog * d)20014 void MessagesManager::open_dialog(Dialog *d) {
20015   CHECK(!td_->auth_manager_->is_bot());
20016   DialogId dialog_id = d->dialog_id;
20017   if (!have_input_peer(dialog_id, AccessRights::Read)) {
20018     return;
20019   }
20020   recently_opened_dialogs_.add_dialog(dialog_id);
20021   if (d->is_opened) {
20022     return;
20023   }
20024   d->is_opened = true;
20025   d->was_opened = true;
20026 
20027   auto min_message_id = MessageId(ServerMessageId(1));
20028   if (d->last_message_id == MessageId() && d->last_read_outbox_message_id < min_message_id && d->messages != nullptr &&
20029       d->messages->message_id < min_message_id) {
20030     Message *m = d->messages.get();
20031     while (m->right != nullptr) {
20032       m = m->right.get();
20033     }
20034     if (m->message_id < min_message_id) {
20035       read_history_inbox(dialog_id, m->message_id, -1, "open_dialog");
20036     }
20037   }
20038 
20039   if (d->has_unload_timeout) {
20040     LOG(INFO) << "Cancel unload timeout for " << dialog_id;
20041     pending_unload_dialog_timeout_.cancel_timeout(dialog_id.get());
20042     d->has_unload_timeout = false;
20043   }
20044 
20045   if (d->new_secret_chat_notification_id.is_valid()) {
20046     remove_new_secret_chat_notification(d, true);
20047   }
20048 
20049   get_dialog_pinned_message(dialog_id, Auto());
20050 
20051   if (d->active_group_call_id.is_valid()) {
20052     td_->group_call_manager_->reload_group_call(d->active_group_call_id, Auto());
20053   }
20054 
20055   switch (dialog_id.get_type()) {
20056     case DialogType::User:
20057       break;
20058     case DialogType::Chat:
20059       td_->contacts_manager_->repair_chat_participants(dialog_id.get_chat_id());
20060       reget_dialog_action_bar(dialog_id, "open_dialog", false);
20061       break;
20062     case DialogType::Channel:
20063       if (!is_broadcast_channel(dialog_id)) {
20064         auto participant_count = td_->contacts_manager_->get_channel_participant_count(dialog_id.get_channel_id());
20065         if (participant_count < 195) {  // include unknown participant_count
20066           td_->contacts_manager_->get_channel_participants(dialog_id.get_channel_id(),
20067                                                            td_api::make_object<td_api::supergroupMembersFilterRecent>(),
20068                                                            string(), 0, 200, 200, Auto());
20069         }
20070       }
20071       get_channel_difference(dialog_id, d->pts, true, "open_dialog");
20072       reget_dialog_action_bar(dialog_id, "open_dialog", false);
20073       break;
20074     case DialogType::SecretChat: {
20075       // to repair dialog action bar
20076       auto user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id());
20077       if (user_id.is_valid()) {
20078         td_->contacts_manager_->reload_user_full(user_id);
20079       }
20080       break;
20081     }
20082     case DialogType::None:
20083     default:
20084       UNREACHABLE();
20085   }
20086 
20087   if (!td_->auth_manager_->is_bot()) {
20088     auto online_count_it = dialog_online_member_counts_.find(dialog_id);
20089     if (online_count_it != dialog_online_member_counts_.end()) {
20090       auto &info = online_count_it->second;
20091       CHECK(!info.is_update_sent);
20092       if (Time::now() - info.updated_time < ONLINE_MEMBER_COUNT_CACHE_EXPIRE_TIME) {
20093         info.is_update_sent = true;
20094         send_update_chat_online_member_count(dialog_id, info.online_member_count);
20095       }
20096     }
20097 
20098     if (d->has_scheduled_database_messages && !d->is_has_scheduled_database_messages_checked) {
20099       CHECK(G()->parameters().use_message_db);
20100 
20101       LOG(INFO) << "Send check has_scheduled_database_messages request";
20102       d->is_has_scheduled_database_messages_checked = true;
20103       G()->td_db()->get_messages_db_async()->get_scheduled_messages(
20104           dialog_id, 1,
20105           PromiseCreator::lambda([actor_id = actor_id(this), dialog_id](vector<MessagesDbDialogMessage> messages) {
20106             if (messages.empty()) {
20107               send_closure(actor_id, &MessagesManager::set_dialog_has_scheduled_database_messages, dialog_id, false);
20108             }
20109           }));
20110     }
20111   }
20112 }
20113 
close_dialog(Dialog * d)20114 void MessagesManager::close_dialog(Dialog *d) {
20115   if (!d->is_opened) {
20116     return;
20117   }
20118   d->is_opened = false;
20119 
20120   auto dialog_id = d->dialog_id;
20121   if (have_input_peer(dialog_id, AccessRights::Write)) {
20122     if (pending_draft_message_timeout_.has_timeout(dialog_id.get())) {
20123       pending_draft_message_timeout_.set_timeout_in(dialog_id.get(), 0.0);
20124     }
20125   } else {
20126     pending_draft_message_timeout_.cancel_timeout(dialog_id.get());
20127   }
20128 
20129   if (have_input_peer(dialog_id, AccessRights::Read)) {
20130     if (pending_message_views_timeout_.has_timeout(dialog_id.get())) {
20131       pending_message_views_timeout_.set_timeout_in(dialog_id.get(), 0.0);
20132     }
20133     if (pending_read_history_timeout_.has_timeout(dialog_id.get())) {
20134       pending_read_history_timeout_.set_timeout_in(dialog_id.get(), 0.0);
20135     }
20136   } else {
20137     pending_message_views_timeout_.cancel_timeout(dialog_id.get());
20138     d->pending_viewed_message_ids.clear();
20139     d->increment_view_counter = false;
20140 
20141     pending_read_history_timeout_.cancel_timeout(dialog_id.get());
20142   }
20143 
20144   if (is_message_unload_enabled()) {
20145     CHECK(!d->has_unload_timeout);
20146     d->has_unload_timeout = true;
20147     pending_unload_dialog_timeout_.set_timeout_in(dialog_id.get(), get_unload_dialog_delay());
20148   }
20149 
20150   for (auto &it : d->pending_viewed_live_locations) {
20151     auto live_location_task_id = it.second;
20152     auto erased_count = viewed_live_location_tasks_.erase(live_location_task_id);
20153     CHECK(erased_count > 0);
20154   }
20155   d->pending_viewed_live_locations.clear();
20156 
20157   switch (dialog_id.get_type()) {
20158     case DialogType::User:
20159       break;
20160     case DialogType::Chat:
20161       break;
20162     case DialogType::Channel:
20163       channel_get_difference_timeout_.cancel_timeout(dialog_id.get());
20164       break;
20165     case DialogType::SecretChat:
20166       break;
20167     case DialogType::None:
20168     default:
20169       UNREACHABLE();
20170   }
20171 
20172   if (!td_->auth_manager_->is_bot()) {
20173     auto online_count_it = dialog_online_member_counts_.find(dialog_id);
20174     if (online_count_it != dialog_online_member_counts_.end()) {
20175       auto &info = online_count_it->second;
20176       info.is_update_sent = false;
20177     }
20178     update_dialog_online_member_count_timeout_.set_timeout_in(dialog_id.get(), ONLINE_MEMBER_COUNT_CACHE_EXPIRE_TIME);
20179   }
20180 }
20181 
get_chat_type_object(DialogId dialog_id) const20182 td_api::object_ptr<td_api::ChatType> MessagesManager::get_chat_type_object(DialogId dialog_id) const {
20183   switch (dialog_id.get_type()) {
20184     case DialogType::User:
20185       return td_api::make_object<td_api::chatTypePrivate>(
20186           td_->contacts_manager_->get_user_id_object(dialog_id.get_user_id(), "chatTypePrivate"));
20187     case DialogType::Chat:
20188       return td_api::make_object<td_api::chatTypeBasicGroup>(
20189           td_->contacts_manager_->get_basic_group_id_object(dialog_id.get_chat_id(), "chatTypeBasicGroup"));
20190     case DialogType::Channel: {
20191       auto channel_id = dialog_id.get_channel_id();
20192       auto channel_type = td_->contacts_manager_->get_channel_type(channel_id);
20193       return td_api::make_object<td_api::chatTypeSupergroup>(
20194           td_->contacts_manager_->get_supergroup_id_object(channel_id, "chatTypeSupergroup"),
20195           channel_type != ContactsManager::ChannelType::Megagroup);
20196     }
20197     case DialogType::SecretChat: {
20198       auto secret_chat_id = dialog_id.get_secret_chat_id();
20199       auto user_id = td_->contacts_manager_->get_secret_chat_user_id(secret_chat_id);
20200       return td_api::make_object<td_api::chatTypeSecret>(
20201           td_->contacts_manager_->get_secret_chat_id_object(secret_chat_id, "chatTypeSecret"),
20202           td_->contacts_manager_->get_user_id_object(user_id, "chatTypeSecret"));
20203     }
20204     case DialogType::None:
20205     default:
20206       UNREACHABLE();
20207       return nullptr;
20208   }
20209 }
20210 
get_chat_action_bar_object(const Dialog * d) const20211 td_api::object_ptr<td_api::ChatActionBar> MessagesManager::get_chat_action_bar_object(const Dialog *d) const {
20212   CHECK(d != nullptr);
20213   auto dialog_type = d->dialog_id.get_type();
20214   if (dialog_type == DialogType::SecretChat) {
20215     auto user_id = td_->contacts_manager_->get_secret_chat_user_id(d->dialog_id.get_secret_chat_id());
20216     if (!user_id.is_valid()) {
20217       return nullptr;
20218     }
20219     const Dialog *user_d = get_dialog(DialogId(user_id));
20220     if (user_d == nullptr || user_d->action_bar == nullptr) {
20221       return nullptr;
20222     }
20223     return user_d->action_bar->get_chat_action_bar_object(DialogType::User, d->folder_id != FolderId::archive());
20224   }
20225 
20226   if (d->action_bar == nullptr) {
20227     return nullptr;
20228   }
20229   return d->action_bar->get_chat_action_bar_object(dialog_type, false);
20230 }
20231 
get_dialog_theme_name(const Dialog * d) const20232 string MessagesManager::get_dialog_theme_name(const Dialog *d) const {
20233   CHECK(d != nullptr);
20234   if (d->dialog_id.get_type() == DialogType::SecretChat) {
20235     auto user_id = td_->contacts_manager_->get_secret_chat_user_id(d->dialog_id.get_secret_chat_id());
20236     if (!user_id.is_valid()) {
20237       return string();
20238     }
20239     d = get_dialog(DialogId(user_id));
20240     if (d == nullptr) {
20241       return string();
20242     }
20243   }
20244   return d->theme_name;
20245 }
20246 
get_chat_join_requests_info_object(const Dialog * d) const20247 td_api::object_ptr<td_api::chatJoinRequestsInfo> MessagesManager::get_chat_join_requests_info_object(
20248     const Dialog *d) const {
20249   if (d->pending_join_request_count == 0) {
20250     return nullptr;
20251   }
20252   return td_api::make_object<td_api::chatJoinRequestsInfo>(
20253       d->pending_join_request_count, td_->contacts_manager_->get_user_ids_object(d->pending_join_request_user_ids,
20254                                                                                  "get_chat_join_requests_info_object"));
20255 }
20256 
get_video_chat_object(const Dialog * d) const20257 td_api::object_ptr<td_api::videoChat> MessagesManager::get_video_chat_object(const Dialog *d) const {
20258   auto active_group_call_id = td_->group_call_manager_->get_group_call_id(d->active_group_call_id, d->dialog_id);
20259   auto default_participant_alias =
20260       d->default_join_group_call_as_dialog_id.is_valid()
20261           ? get_message_sender_object_const(td_, d->default_join_group_call_as_dialog_id, "get_video_chat_object")
20262           : nullptr;
20263   return make_tl_object<td_api::videoChat>(active_group_call_id.get(),
20264                                            active_group_call_id.is_valid() ? !d->is_group_call_empty : false,
20265                                            std::move(default_participant_alias));
20266 }
20267 
get_default_sender_id_object(const Dialog * d) const20268 td_api::object_ptr<td_api::MessageSender> MessagesManager::get_default_sender_id_object(const Dialog *d) const {
20269   auto as_dialog_id = d->default_send_message_as_dialog_id;
20270   return as_dialog_id.is_valid() ? get_message_sender_object_const(td_, as_dialog_id, "get_default_sender_id_object")
20271                                  : nullptr;
20272 }
20273 
get_chat_object(const Dialog * d) const20274 td_api::object_ptr<td_api::chat> MessagesManager::get_chat_object(const Dialog *d) const {
20275   CHECK(d != nullptr);
20276 
20277   auto chat_source = is_dialog_sponsored(d) ? sponsored_dialog_source_.get_chat_source_object() : nullptr;
20278 
20279   bool can_delete_for_self = false;
20280   bool can_delete_for_all_users = false;
20281   if (chat_source != nullptr) {
20282     switch (chat_source->get_id()) {
20283       case td_api::chatSourcePublicServiceAnnouncement::ID:
20284         // can delete for self (but only while removing from dialog list)
20285         can_delete_for_self = true;
20286         break;
20287       default:
20288         // can't delete
20289         break;
20290     }
20291   } else if (!td_->auth_manager_->is_bot() && have_input_peer(d->dialog_id, AccessRights::Read)) {
20292     switch (d->dialog_id.get_type()) {
20293       case DialogType::User:
20294         can_delete_for_self = true;
20295         can_delete_for_all_users = G()->shared_config().get_option_boolean("revoke_pm_inbox", true);
20296         if (d->dialog_id == get_my_dialog_id() || td_->contacts_manager_->is_user_deleted(d->dialog_id.get_user_id()) ||
20297             td_->contacts_manager_->is_user_bot(d->dialog_id.get_user_id())) {
20298           can_delete_for_all_users = false;
20299         }
20300         break;
20301       case DialogType::Chat:
20302         // chats can be deleted only for self with deleteChatHistory
20303         can_delete_for_self = true;
20304         break;
20305       case DialogType::Channel:
20306         if (is_broadcast_channel(d->dialog_id) ||
20307             td_->contacts_manager_->is_channel_public(d->dialog_id.get_channel_id())) {
20308           // deleteChatHistory can't be used in channels and public supergroups
20309         } else {
20310           // private supergroups can be deleted for self
20311           can_delete_for_self = true;
20312         }
20313         break;
20314       case DialogType::SecretChat:
20315         if (td_->contacts_manager_->get_secret_chat_state(d->dialog_id.get_secret_chat_id()) ==
20316             SecretChatState::Closed) {
20317           // in a closed secret chats there is no way to delete messages for both users
20318           can_delete_for_self = true;
20319         } else {
20320           // active secret chats can be deleted only for both users
20321           can_delete_for_all_users = true;
20322         }
20323         break;
20324       case DialogType::None:
20325       default:
20326         UNREACHABLE();
20327     }
20328   }
20329 
20330   // TODO hide/show draft message when can_send_message(dialog_id) changes
20331   auto draft_message = can_send_message(d->dialog_id).is_ok() ? get_draft_message_object(d->draft_message) : nullptr;
20332 
20333   return make_tl_object<td_api::chat>(
20334       d->dialog_id.get(), get_chat_type_object(d->dialog_id), get_dialog_title(d->dialog_id),
20335       get_chat_photo_info_object(td_->file_manager_.get(), get_dialog_photo(d->dialog_id)),
20336       get_dialog_default_permissions(d->dialog_id).get_chat_permissions_object(),
20337       get_message_object(d->dialog_id, get_message(d, d->last_message_id), "get_chat_object"),
20338       get_chat_positions_object(d), get_default_sender_id_object(d), get_dialog_has_protected_content(d->dialog_id),
20339       d->is_marked_as_unread, d->is_blocked, get_dialog_has_scheduled_messages(d), can_delete_for_self,
20340       can_delete_for_all_users, can_report_dialog(d->dialog_id), d->notification_settings.silent_send_message,
20341       d->server_unread_count + d->local_unread_count, d->last_read_inbox_message_id.get(),
20342       d->last_read_outbox_message_id.get(), d->unread_mention_count,
20343       get_chat_notification_settings_object(&d->notification_settings),
20344       d->message_ttl_setting.get_message_ttl_setting_object(), get_dialog_theme_name(d), get_chat_action_bar_object(d),
20345       get_video_chat_object(d), get_chat_join_requests_info_object(d), d->reply_markup_message_id.get(),
20346       std::move(draft_message), d->client_data);
20347 }
20348 
get_chat_object(DialogId dialog_id) const20349 tl_object_ptr<td_api::chat> MessagesManager::get_chat_object(DialogId dialog_id) const {
20350   return get_chat_object(get_dialog(dialog_id));
20351 }
20352 
get_chats_object(int32 total_count,const vector<DialogId> & dialog_ids)20353 tl_object_ptr<td_api::chats> MessagesManager::get_chats_object(int32 total_count, const vector<DialogId> &dialog_ids) {
20354   if (total_count == -1) {
20355     total_count = narrow_cast<int32>(dialog_ids.size());
20356   }
20357   return td_api::make_object<td_api::chats>(total_count,
20358                                             transform(dialog_ids, [](DialogId dialog_id) { return dialog_id.get(); }));
20359 }
20360 
get_chats_object(const std::pair<int32,vector<DialogId>> & dialog_ids)20361 tl_object_ptr<td_api::chats> MessagesManager::get_chats_object(const std::pair<int32, vector<DialogId>> &dialog_ids) {
20362   return get_chats_object(dialog_ids.first, dialog_ids.second);
20363 }
20364 
get_chat_filter_object(DialogFilterId dialog_filter_id) const20365 td_api::object_ptr<td_api::chatFilter> MessagesManager::get_chat_filter_object(DialogFilterId dialog_filter_id) const {
20366   CHECK(!td_->auth_manager_->is_bot());
20367   auto filter = get_dialog_filter(dialog_filter_id);
20368   if (filter == nullptr) {
20369     return nullptr;
20370   }
20371 
20372   return get_chat_filter_object(filter);
20373 }
20374 
get_chat_filter_object(const DialogFilter * filter) const20375 td_api::object_ptr<td_api::chatFilter> MessagesManager::get_chat_filter_object(const DialogFilter *filter) const {
20376   auto get_chat_ids = [this,
20377                        dialog_filter_id = filter->dialog_filter_id](const vector<InputDialogId> &input_dialog_ids) {
20378     vector<int64> chat_ids;
20379     chat_ids.reserve(input_dialog_ids.size());
20380     for (auto &input_dialog_id : input_dialog_ids) {
20381       auto dialog_id = input_dialog_id.get_dialog_id();
20382       const Dialog *d = get_dialog(dialog_id);
20383       if (d != nullptr) {
20384         if (d->order != DEFAULT_ORDER) {
20385           chat_ids.push_back(dialog_id.get());
20386         } else {
20387           LOG(INFO) << "Skip nonjoined " << dialog_id << " from " << dialog_filter_id;
20388         }
20389       } else {
20390         LOG(ERROR) << "Can't find " << dialog_id << " from " << dialog_filter_id;
20391       }
20392     }
20393     return chat_ids;
20394   };
20395   return td_api::make_object<td_api::chatFilter>(
20396       filter->title, filter->get_icon_name(), get_chat_ids(filter->pinned_dialog_ids),
20397       get_chat_ids(filter->included_dialog_ids), get_chat_ids(filter->excluded_dialog_ids), filter->exclude_muted,
20398       filter->exclude_read, filter->exclude_archived, filter->include_contacts, filter->include_non_contacts,
20399       filter->include_bots, filter->include_groups, filter->include_channels);
20400 }
20401 
20402 td_api::object_ptr<td_api::updateScopeNotificationSettings>
get_update_scope_notification_settings_object(NotificationSettingsScope scope) const20403 MessagesManager::get_update_scope_notification_settings_object(NotificationSettingsScope scope) const {
20404   auto notification_settings = get_scope_notification_settings(scope);
20405   CHECK(notification_settings != nullptr);
20406   return td_api::make_object<td_api::updateScopeNotificationSettings>(
20407       get_notification_settings_scope_object(scope), get_scope_notification_settings_object(notification_settings));
20408 }
20409 
get_dialog_mute_until(DialogId dialog_id,const Dialog * d) const20410 std::pair<bool, int32> MessagesManager::get_dialog_mute_until(DialogId dialog_id, const Dialog *d) const {
20411   CHECK(!td_->auth_manager_->is_bot());
20412   if (d == nullptr || !d->notification_settings.is_synchronized) {
20413     return {false, get_scope_mute_until(dialog_id)};
20414   }
20415 
20416   return {d->notification_settings.is_use_default_fixed, get_dialog_mute_until(d)};
20417 }
20418 
get_dialog_notification_setting_scope(DialogId dialog_id) const20419 NotificationSettingsScope MessagesManager::get_dialog_notification_setting_scope(DialogId dialog_id) const {
20420   switch (dialog_id.get_type()) {
20421     case DialogType::User:
20422     case DialogType::SecretChat:
20423       return NotificationSettingsScope::Private;
20424     case DialogType::Chat:
20425       return NotificationSettingsScope::Group;
20426     case DialogType::Channel:
20427       return is_broadcast_channel(dialog_id) ? NotificationSettingsScope::Channel : NotificationSettingsScope::Group;
20428     case DialogType::None:
20429     default:
20430       UNREACHABLE();
20431       return NotificationSettingsScope::Private;
20432   }
20433 }
20434 
get_scope_mute_until(DialogId dialog_id) const20435 int32 MessagesManager::get_scope_mute_until(DialogId dialog_id) const {
20436   switch (dialog_id.get_type()) {
20437     case DialogType::User:
20438     case DialogType::SecretChat:
20439       return users_notification_settings_.mute_until;
20440     case DialogType::Chat:
20441       return chats_notification_settings_.mute_until;
20442     case DialogType::Channel:
20443       return is_broadcast_channel(dialog_id) ? channels_notification_settings_.mute_until
20444                                              : chats_notification_settings_.mute_until;
20445     case DialogType::None:
20446     default:
20447       UNREACHABLE();
20448       return 0;
20449   }
20450 }
20451 
get_dialog_notification_settings_exceptions(NotificationSettingsScope scope,bool filter_scope,bool compare_sound,bool force,Promise<Unit> && promise)20452 vector<DialogId> MessagesManager::get_dialog_notification_settings_exceptions(NotificationSettingsScope scope,
20453                                                                               bool filter_scope, bool compare_sound,
20454                                                                               bool force, Promise<Unit> &&promise) {
20455   CHECK(!td_->auth_manager_->is_bot());
20456   bool have_all_dialogs = true;
20457   for (const auto &list : dialog_folders_) {
20458     if (list.second.folder_last_dialog_date_ != MAX_DIALOG_DATE) {
20459       have_all_dialogs = false;
20460     }
20461   }
20462 
20463   if (have_all_dialogs || force) {
20464     vector<DialogDate> ordered_dialogs;
20465     auto my_dialog_id = get_my_dialog_id();
20466     for (const auto &list : dialog_folders_) {
20467       for (const auto &dialog_date : list.second.ordered_dialogs_) {
20468         auto dialog_id = dialog_date.get_dialog_id();
20469         if (filter_scope && get_dialog_notification_setting_scope(dialog_id) != scope) {
20470           continue;
20471         }
20472         if (dialog_id == my_dialog_id) {
20473           continue;
20474         }
20475 
20476         const Dialog *d = get_dialog(dialog_id);
20477         CHECK(d != nullptr);
20478         LOG_CHECK(d->folder_id == list.first)
20479             << list.first << ' ' << dialog_id << ' ' << d->folder_id << ' ' << d->order;
20480         if (d->order == DEFAULT_ORDER) {
20481           break;
20482         }
20483         if (are_default_dialog_notification_settings(d->notification_settings, compare_sound)) {
20484           continue;
20485         }
20486         if (is_dialog_message_notification_disabled(dialog_id, std::numeric_limits<int32>::max())) {
20487           continue;
20488         }
20489         ordered_dialogs.push_back(DialogDate(get_dialog_base_order(d), dialog_id));
20490       }
20491     }
20492     std::sort(ordered_dialogs.begin(), ordered_dialogs.end());
20493 
20494     vector<DialogId> result;
20495     for (auto &dialog_date : ordered_dialogs) {
20496       CHECK(result.empty() || result.back() != dialog_date.get_dialog_id());
20497       result.push_back(dialog_date.get_dialog_id());
20498     }
20499     promise.set_value(Unit());
20500     return result;
20501   }
20502 
20503   for (const auto &folder : dialog_folders_) {
20504     load_folder_dialog_list(folder.first, MAX_GET_DIALOGS, true);
20505   }
20506 
20507   td_->create_handler<GetNotifySettingsExceptionsQuery>(std::move(promise))->send(scope, filter_scope, compare_sound);
20508   return {};
20509 }
20510 
get_scope_notification_settings(NotificationSettingsScope scope,Promise<Unit> && promise)20511 const ScopeNotificationSettings *MessagesManager::get_scope_notification_settings(NotificationSettingsScope scope,
20512                                                                                   Promise<Unit> &&promise) {
20513   const ScopeNotificationSettings *notification_settings = get_scope_notification_settings(scope);
20514   CHECK(notification_settings != nullptr);
20515   if (!notification_settings->is_synchronized && !td_->auth_manager_->is_bot()) {
20516     send_get_scope_notification_settings_query(scope, std::move(promise));
20517     return nullptr;
20518   }
20519 
20520   promise.set_value(Unit());
20521   return notification_settings;
20522 }
20523 
get_dialog_notification_settings(DialogId dialog_id,bool force)20524 DialogNotificationSettings *MessagesManager::get_dialog_notification_settings(DialogId dialog_id, bool force) {
20525   Dialog *d = get_dialog_force(dialog_id, "get_dialog_notification_settings");
20526   if (d == nullptr) {
20527     return nullptr;
20528   }
20529   if (!force && !have_input_peer(dialog_id, AccessRights::Read)) {
20530     return nullptr;
20531   }
20532   return &d->notification_settings;
20533 }
20534 
get_scope_notification_settings(NotificationSettingsScope scope)20535 ScopeNotificationSettings *MessagesManager::get_scope_notification_settings(NotificationSettingsScope scope) {
20536   switch (scope) {
20537     case NotificationSettingsScope::Private:
20538       return &users_notification_settings_;
20539     case NotificationSettingsScope::Group:
20540       return &chats_notification_settings_;
20541     case NotificationSettingsScope::Channel:
20542       return &channels_notification_settings_;
20543     default:
20544       UNREACHABLE();
20545       return nullptr;
20546   }
20547 }
20548 
get_scope_notification_settings(NotificationSettingsScope scope) const20549 const ScopeNotificationSettings *MessagesManager::get_scope_notification_settings(
20550     NotificationSettingsScope scope) const {
20551   switch (scope) {
20552     case NotificationSettingsScope::Private:
20553       return &users_notification_settings_;
20554     case NotificationSettingsScope::Group:
20555       return &chats_notification_settings_;
20556     case NotificationSettingsScope::Channel:
20557       return &channels_notification_settings_;
20558     default:
20559       UNREACHABLE();
20560       return nullptr;
20561   }
20562 }
20563 
get_input_notify_peer(DialogId dialog_id) const20564 tl_object_ptr<telegram_api::InputNotifyPeer> MessagesManager::get_input_notify_peer(DialogId dialog_id) const {
20565   if (get_dialog(dialog_id) == nullptr) {
20566     return nullptr;
20567   }
20568   auto input_peer = get_input_peer(dialog_id, AccessRights::Read);
20569   if (input_peer == nullptr) {
20570     return nullptr;
20571   }
20572   return make_tl_object<telegram_api::inputNotifyPeer>(std::move(input_peer));
20573 }
20574 
set_dialog_notification_settings(DialogId dialog_id,tl_object_ptr<td_api::chatNotificationSettings> && notification_settings)20575 Status MessagesManager::set_dialog_notification_settings(
20576     DialogId dialog_id, tl_object_ptr<td_api::chatNotificationSettings> &&notification_settings) {
20577   CHECK(!td_->auth_manager_->is_bot());
20578   auto current_settings = get_dialog_notification_settings(dialog_id, false);
20579   if (current_settings == nullptr) {
20580     return Status::Error(400, "Wrong chat identifier specified");
20581   }
20582   if (dialog_id == get_my_dialog_id()) {
20583     return Status::Error(400, "Notification settings of the Saved Messages chat can't be changed");
20584   }
20585 
20586   TRY_RESULT(new_settings, ::td::get_dialog_notification_settings(std::move(notification_settings),
20587                                                                   current_settings->silent_send_message));
20588   if (update_dialog_notification_settings(dialog_id, current_settings, new_settings)) {
20589     update_dialog_notification_settings_on_server(dialog_id, false);
20590   }
20591   return Status::OK();
20592 }
20593 
set_scope_notification_settings(NotificationSettingsScope scope,tl_object_ptr<td_api::scopeNotificationSettings> && notification_settings)20594 Status MessagesManager::set_scope_notification_settings(
20595     NotificationSettingsScope scope, tl_object_ptr<td_api::scopeNotificationSettings> &&notification_settings) {
20596   CHECK(!td_->auth_manager_->is_bot());
20597   TRY_RESULT(new_settings, ::td::get_scope_notification_settings(std::move(notification_settings)));
20598   if (update_scope_notification_settings(scope, get_scope_notification_settings(scope), new_settings)) {
20599     update_scope_notification_settings_on_server(scope, 0);
20600   }
20601   return Status::OK();
20602 }
20603 
20604 class MessagesManager::UpdateScopeNotificationSettingsOnServerLogEvent {
20605  public:
20606   NotificationSettingsScope scope_;
20607 
20608   template <class StorerT>
store(StorerT & storer) const20609   void store(StorerT &storer) const {
20610     td::store(scope_, storer);
20611   }
20612 
20613   template <class ParserT>
parse(ParserT & parser)20614   void parse(ParserT &parser) {
20615     td::parse(scope_, parser);
20616   }
20617 };
20618 
save_update_scope_notification_settings_on_server_log_event(NotificationSettingsScope scope)20619 uint64 MessagesManager::save_update_scope_notification_settings_on_server_log_event(NotificationSettingsScope scope) {
20620   UpdateScopeNotificationSettingsOnServerLogEvent log_event{scope};
20621   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::UpdateScopeNotificationSettingsOnServer,
20622                     get_log_event_storer(log_event));
20623 }
20624 
update_scope_notification_settings_on_server(NotificationSettingsScope scope,uint64 log_event_id)20625 void MessagesManager::update_scope_notification_settings_on_server(NotificationSettingsScope scope,
20626                                                                    uint64 log_event_id) {
20627   CHECK(!td_->auth_manager_->is_bot());
20628   if (log_event_id == 0) {
20629     log_event_id = save_update_scope_notification_settings_on_server_log_event(scope);
20630   }
20631 
20632   LOG(INFO) << "Update " << scope << " notification settings on server with log_event " << log_event_id;
20633   td_->create_handler<UpdateScopeNotifySettingsQuery>(get_erase_log_event_promise(log_event_id))
20634       ->send(scope, *get_scope_notification_settings(scope));
20635 }
20636 
reset_all_notification_settings()20637 void MessagesManager::reset_all_notification_settings() {
20638   CHECK(!td_->auth_manager_->is_bot());
20639   DialogNotificationSettings new_dialog_settings;
20640   ScopeNotificationSettings new_scope_settings;
20641   new_dialog_settings.is_synchronized = true;
20642   new_scope_settings.is_synchronized = true;
20643 
20644   update_scope_notification_settings(NotificationSettingsScope::Private, &users_notification_settings_,
20645                                      new_scope_settings);
20646   update_scope_notification_settings(NotificationSettingsScope::Group, &chats_notification_settings_,
20647                                      new_scope_settings);
20648   update_scope_notification_settings(NotificationSettingsScope::Channel, &channels_notification_settings_,
20649                                      new_scope_settings);
20650 
20651   for (auto &dialog : dialogs_) {
20652     Dialog *d = dialog.second.get();
20653     update_dialog_notification_settings(d->dialog_id, &d->notification_settings, new_dialog_settings);
20654   }
20655   reset_all_notification_settings_on_server(0);
20656 }
20657 
20658 class MessagesManager::ResetAllNotificationSettingsOnServerLogEvent {
20659  public:
20660   template <class StorerT>
store(StorerT & storer) const20661   void store(StorerT &storer) const {
20662   }
20663 
20664   template <class ParserT>
parse(ParserT & parser)20665   void parse(ParserT &parser) {
20666   }
20667 };
20668 
save_reset_all_notification_settings_on_server_log_event()20669 uint64 MessagesManager::save_reset_all_notification_settings_on_server_log_event() {
20670   ResetAllNotificationSettingsOnServerLogEvent log_event;
20671   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::ResetAllNotificationSettingsOnServer,
20672                     get_log_event_storer(log_event));
20673 }
20674 
reset_all_notification_settings_on_server(uint64 log_event_id)20675 void MessagesManager::reset_all_notification_settings_on_server(uint64 log_event_id) {
20676   CHECK(!td_->auth_manager_->is_bot());
20677   if (log_event_id == 0) {
20678     log_event_id = save_reset_all_notification_settings_on_server_log_event();
20679   }
20680 
20681   LOG(INFO) << "Reset all notification settings";
20682   td_->create_handler<ResetNotifySettingsQuery>(get_erase_log_event_promise(log_event_id))->send();
20683 }
20684 
get_dialog_history(DialogId dialog_id,MessageId from_message_id,int32 offset,int32 limit,int left_tries,bool only_local,Promise<Unit> && promise)20685 tl_object_ptr<td_api::messages> MessagesManager::get_dialog_history(DialogId dialog_id, MessageId from_message_id,
20686                                                                     int32 offset, int32 limit, int left_tries,
20687                                                                     bool only_local, Promise<Unit> &&promise) {
20688   if (limit <= 0) {
20689     promise.set_error(Status::Error(400, "Parameter limit must be positive"));
20690     return nullptr;
20691   }
20692   if (limit > MAX_GET_HISTORY) {
20693     limit = MAX_GET_HISTORY;
20694   }
20695   if (offset > 0) {
20696     promise.set_error(Status::Error(400, "Parameter offset must be non-positive"));
20697     return nullptr;
20698   }
20699   if (offset <= -MAX_GET_HISTORY) {
20700     promise.set_error(Status::Error(400, "Parameter offset must be greater than -100"));
20701     return nullptr;
20702   }
20703   if (offset < -limit) {
20704     promise.set_error(Status::Error(400, "Parameter offset must be greater than or equal to -limit"));
20705     return nullptr;
20706   }
20707   bool is_limit_increased = false;
20708   if (limit == -offset) {
20709     limit++;
20710     is_limit_increased = true;
20711   }
20712   CHECK(0 < limit && limit <= MAX_GET_HISTORY);
20713   CHECK(-limit < offset && offset <= 0);
20714 
20715   if (from_message_id == MessageId() || from_message_id.get() > MessageId::max().get()) {
20716     from_message_id = MessageId::max();
20717   }
20718   if (!from_message_id.is_valid()) {
20719     promise.set_error(Status::Error(400, "Invalid value of parameter from_message_id specified"));
20720     return nullptr;
20721   }
20722 
20723   const Dialog *d = get_dialog_force(dialog_id, "get_dialog_history");
20724   if (d == nullptr) {
20725     promise.set_error(Status::Error(400, "Chat not found"));
20726     return nullptr;
20727   }
20728   if (!have_input_peer(dialog_id, AccessRights::Read)) {
20729     promise.set_error(Status::Error(400, "Can't access the chat"));
20730     return nullptr;
20731   }
20732 
20733   LOG(INFO) << "Get " << (only_local ? "local " : "") << "history in " << dialog_id << " from " << from_message_id
20734             << " with offset " << offset << " and limit " << limit << ", " << left_tries
20735             << " tries left. Last read inbox message is " << d->last_read_inbox_message_id
20736             << ", last read outbox message is " << d->last_read_outbox_message_id
20737             << ", have_full_history = " << d->have_full_history;
20738 
20739   MessagesConstIterator p(d, from_message_id);
20740   LOG(DEBUG) << "Iterator points to " << (*p ? (*p)->message_id : MessageId());
20741   bool from_the_end = (d->last_message_id != MessageId() && from_message_id > d->last_message_id) ||
20742                       from_message_id >= MessageId::max();
20743 
20744   if (from_the_end) {
20745     limit += offset;
20746     offset = 0;
20747     if (d->last_message_id == MessageId()) {
20748       p = MessagesConstIterator();
20749     }
20750   } else {
20751     bool have_a_gap = false;
20752     if (*p == nullptr) {
20753       // there is no gap if from_message_id is less than first message in the dialog
20754       if (left_tries == 0 && d->messages != nullptr && offset < 0) {
20755         const Message *cur = d->messages.get();
20756         while (cur->left != nullptr) {
20757           cur = cur->left.get();
20758         }
20759         CHECK(cur->message_id > from_message_id);
20760         from_message_id = cur->message_id;
20761         p = MessagesConstIterator(d, from_message_id);
20762       } else {
20763         have_a_gap = true;
20764       }
20765     } else if ((*p)->message_id != from_message_id) {
20766       CHECK((*p)->message_id < from_message_id);
20767       if (!(*p)->have_next && (d->last_message_id == MessageId() || (*p)->message_id < d->last_message_id)) {
20768         have_a_gap = true;
20769       }
20770     }
20771 
20772     if (have_a_gap) {
20773       LOG(INFO) << "Have a gap near message to get chat history from";
20774       p = MessagesConstIterator();
20775     }
20776     if (*p != nullptr && (*p)->message_id == from_message_id) {
20777       if (offset < 0) {
20778         offset++;
20779       } else {
20780         --p;
20781       }
20782     }
20783 
20784     while (*p != nullptr && offset < 0) {
20785       ++p;
20786       if (*p) {
20787         ++offset;
20788         from_message_id = (*p)->message_id;
20789       }
20790     }
20791 
20792     if (offset < 0 && ((d->last_message_id != MessageId() && from_message_id >= d->last_message_id) ||
20793                        (!have_a_gap && left_tries == 0))) {
20794       CHECK(!have_a_gap);
20795       limit += offset;
20796       offset = 0;
20797       p = MessagesConstIterator(d, from_message_id);
20798     }
20799 
20800     if (!have_a_gap && offset < 0) {
20801       offset--;
20802     }
20803   }
20804 
20805   LOG(INFO) << "Iterator after applying offset points to " << (*p ? (*p)->message_id : MessageId())
20806             << ", offset = " << offset << ", limit = " << limit << ", from_the_end = " << from_the_end;
20807   vector<tl_object_ptr<td_api::message>> messages;
20808   if (*p != nullptr && offset == 0) {
20809     while (*p != nullptr && messages.size() < static_cast<size_t>(limit)) {
20810       messages.push_back(get_message_object(dialog_id, *p, "get_dialog_history"));
20811       from_message_id = (*p)->message_id;
20812       from_the_end = false;
20813       --p;
20814     }
20815   }
20816 
20817   if (!messages.empty()) {
20818     // maybe need some messages
20819     CHECK(offset == 0);
20820     preload_newer_messages(d, MessageId(messages[0]->id_));
20821     preload_older_messages(d, MessageId(messages.back()->id_));
20822   } else if (messages.size() < static_cast<size_t>(limit) && left_tries != 0 &&
20823              !(d->is_empty && d->have_full_history && left_tries < 3)) {
20824     // there can be more messages in the database or on the server, need to load them
20825     if (from_the_end) {
20826       from_message_id = MessageId();
20827     }
20828     send_closure_later(actor_id(this), &MessagesManager::load_messages, dialog_id, from_message_id, offset,
20829                        limit - static_cast<int32>(messages.size()), left_tries, only_local, std::move(promise));
20830     return nullptr;
20831   }
20832 
20833   LOG(INFO) << "Have " << messages.size() << " messages out of requested "
20834             << (is_limit_increased ? "increased " : "exact ") << limit;
20835   if (is_limit_increased && static_cast<size_t>(limit) == messages.size()) {
20836     messages.pop_back();
20837   }
20838 
20839   LOG(INFO) << "Return " << messages.size() << " messages in result to getChatHistory";
20840   promise.set_value(Unit());                                   // can return some messages
20841   return get_messages_object(-1, std::move(messages), false);  // TODO return real total_count of messages in the dialog
20842 }
20843 
20844 class MessagesManager::ReadHistoryOnServerLogEvent {
20845  public:
20846   DialogId dialog_id_;
20847   MessageId max_message_id_;
20848 
20849   template <class StorerT>
store(StorerT & storer) const20850   void store(StorerT &storer) const {
20851     td::store(dialog_id_, storer);
20852     td::store(max_message_id_, storer);
20853   }
20854 
20855   template <class ParserT>
parse(ParserT & parser)20856   void parse(ParserT &parser) {
20857     td::parse(dialog_id_, parser);
20858     td::parse(max_message_id_, parser);
20859   }
20860 };
20861 
20862 class MessagesManager::ReadHistoryInSecretChatLogEvent {
20863  public:
20864   DialogId dialog_id_;
20865   int32 max_date_ = 0;
20866 
20867   template <class StorerT>
store(StorerT & storer) const20868   void store(StorerT &storer) const {
20869     td::store(dialog_id_, storer);
20870     td::store(max_date_, storer);
20871   }
20872 
20873   template <class ParserT>
parse(ParserT & parser)20874   void parse(ParserT &parser) {
20875     td::parse(dialog_id_, parser);
20876     td::parse(max_date_, parser);
20877   }
20878 };
20879 
20880 class MessagesManager::ReadMessageThreadHistoryOnServerLogEvent {
20881  public:
20882   DialogId dialog_id_;
20883   MessageId top_thread_message_id_;
20884   MessageId max_message_id_;
20885 
20886   template <class StorerT>
store(StorerT & storer) const20887   void store(StorerT &storer) const {
20888     td::store(dialog_id_, storer);
20889     td::store(top_thread_message_id_, storer);
20890     td::store(max_message_id_, storer);
20891   }
20892 
20893   template <class ParserT>
parse(ParserT & parser)20894   void parse(ParserT &parser) {
20895     td::parse(dialog_id_, parser);
20896     td::parse(top_thread_message_id_, parser);
20897     td::parse(max_message_id_, parser);
20898   }
20899 };
20900 
read_history_on_server(Dialog * d,MessageId max_message_id)20901 void MessagesManager::read_history_on_server(Dialog *d, MessageId max_message_id) {
20902   if (td_->auth_manager_->is_bot()) {
20903     return;
20904   }
20905 
20906   CHECK(d != nullptr);
20907   CHECK(!max_message_id.is_scheduled());
20908 
20909   auto dialog_id = d->dialog_id;
20910   LOG(INFO) << "Read history in " << dialog_id << " on server up to " << max_message_id;
20911 
20912   bool is_secret = dialog_id.get_type() == DialogType::SecretChat;
20913   if (is_secret) {
20914     auto *m = get_message_force(d, max_message_id, "read_history_on_server");
20915     if (m == nullptr) {
20916       LOG(ERROR) << "Failed to read history in " << dialog_id << " up to " << max_message_id;
20917       return;
20918     }
20919 
20920     ReadHistoryInSecretChatLogEvent log_event;
20921     log_event.dialog_id_ = dialog_id;
20922     log_event.max_date_ = m->date;
20923     add_log_event(d->read_history_log_event_ids[0], get_log_event_storer(log_event),
20924                   LogEvent::HandlerType::ReadHistoryInSecretChat, "read history");
20925 
20926     d->last_read_inbox_message_date = m->date;
20927   } else if (G()->parameters().use_message_db) {
20928     ReadHistoryOnServerLogEvent log_event;
20929     log_event.dialog_id_ = dialog_id;
20930     log_event.max_message_id_ = max_message_id;
20931     add_log_event(d->read_history_log_event_ids[0], get_log_event_storer(log_event),
20932                   LogEvent::HandlerType::ReadHistoryOnServer, "read history");
20933   }
20934 
20935   d->updated_read_history_message_ids.insert(MessageId());
20936 
20937   bool need_delay = d->is_opened && !is_secret &&
20938                     (d->server_unread_count > 0 || (!need_unread_counter(d->order) && d->last_message_id.is_valid() &&
20939                                                     max_message_id < d->last_message_id));
20940   pending_read_history_timeout_.set_timeout_in(dialog_id.get(), need_delay ? MIN_READ_HISTORY_DELAY : 0);
20941 }
20942 
read_message_thread_history_on_server(Dialog * d,MessageId top_thread_message_id,MessageId max_message_id,MessageId last_message_id)20943 void MessagesManager::read_message_thread_history_on_server(Dialog *d, MessageId top_thread_message_id,
20944                                                             MessageId max_message_id, MessageId last_message_id) {
20945   if (td_->auth_manager_->is_bot()) {
20946     return;
20947   }
20948 
20949   CHECK(d != nullptr);
20950   CHECK(top_thread_message_id.is_valid());
20951   CHECK(top_thread_message_id.is_server());
20952   CHECK(max_message_id.is_server());
20953 
20954   auto dialog_id = d->dialog_id;
20955   LOG(INFO) << "Read history in thread of " << top_thread_message_id << " in " << dialog_id << " on server up to "
20956             << max_message_id;
20957 
20958   if (G()->parameters().use_message_db) {
20959     ReadMessageThreadHistoryOnServerLogEvent log_event;
20960     log_event.dialog_id_ = dialog_id;
20961     log_event.top_thread_message_id_ = top_thread_message_id;
20962     log_event.max_message_id_ = max_message_id;
20963     add_log_event(d->read_history_log_event_ids[top_thread_message_id.get()], get_log_event_storer(log_event),
20964                   LogEvent::HandlerType::ReadMessageThreadHistoryOnServer, "read history");
20965   }
20966 
20967   d->updated_read_history_message_ids.insert(top_thread_message_id);
20968 
20969   bool need_delay = d->is_opened && last_message_id.is_valid() && max_message_id < last_message_id;
20970   pending_read_history_timeout_.set_timeout_in(dialog_id.get(), need_delay ? MIN_READ_HISTORY_DELAY : 0);
20971 }
20972 
do_read_history_on_server(DialogId dialog_id)20973 void MessagesManager::do_read_history_on_server(DialogId dialog_id) {
20974   if (G()->close_flag()) {
20975     return;
20976   }
20977 
20978   Dialog *d = get_dialog(dialog_id);
20979   CHECK(d != nullptr);
20980 
20981   for (auto top_thread_message_id : d->updated_read_history_message_ids) {
20982     if (!top_thread_message_id.is_valid()) {
20983       read_history_on_server_impl(d, MessageId());
20984     } else {
20985       read_message_thread_history_on_server_impl(d, top_thread_message_id, MessageId());
20986     }
20987   }
20988   reset_to_empty(d->updated_read_history_message_ids);
20989 }
20990 
read_history_on_server_impl(Dialog * d,MessageId max_message_id)20991 void MessagesManager::read_history_on_server_impl(Dialog *d, MessageId max_message_id) {
20992   CHECK(d != nullptr);
20993   auto dialog_id = d->dialog_id;
20994 
20995   {
20996     auto message_id = d->last_read_inbox_message_id;
20997     if (dialog_id.get_type() != DialogType::SecretChat) {
20998       message_id = message_id.get_prev_server_message_id();
20999     }
21000     if (message_id > max_message_id) {
21001       max_message_id = message_id;
21002     }
21003   }
21004 
21005   Promise<> promise;
21006   if (d->read_history_log_event_ids[0].log_event_id != 0) {
21007     d->read_history_log_event_ids[0].generation++;
21008     promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_id,
21009                                       generation = d->read_history_log_event_ids[0].generation](Result<Unit> result) {
21010       if (!G()->close_flag()) {
21011         send_closure(actor_id, &MessagesManager::on_read_history_finished, dialog_id, MessageId(), generation);
21012       }
21013     });
21014   }
21015   if (d->need_repair_server_unread_count && need_unread_counter(d->order)) {
21016     repair_server_unread_count(dialog_id, d->server_unread_count);
21017   }
21018 
21019   if (!max_message_id.is_valid() || !have_input_peer(dialog_id, AccessRights::Read)) {
21020     return promise.set_value(Unit());
21021   }
21022 
21023   LOG(INFO) << "Send read history request in " << dialog_id << " up to " << max_message_id;
21024   switch (dialog_id.get_type()) {
21025     case DialogType::User:
21026     case DialogType::Chat:
21027       td_->create_handler<ReadHistoryQuery>(std::move(promise))->send(dialog_id, max_message_id);
21028       break;
21029     case DialogType::Channel: {
21030       auto channel_id = dialog_id.get_channel_id();
21031       td_->create_handler<ReadChannelHistoryQuery>(std::move(promise))->send(channel_id, max_message_id);
21032       break;
21033     }
21034     case DialogType::SecretChat: {
21035       auto secret_chat_id = dialog_id.get_secret_chat_id();
21036       auto date = d->last_read_inbox_message_date;
21037       auto *m = get_message_force(d, max_message_id, "read_history_on_server_impl");
21038       if (m != nullptr && m->date > date) {
21039         date = m->date;
21040       }
21041       if (date == 0) {
21042         LOG(ERROR) << "Don't know last read inbox message date in " << dialog_id;
21043         return promise.set_value(Unit());
21044       }
21045       send_closure(G()->secret_chats_manager(), &SecretChatsManager::send_read_history, secret_chat_id, date,
21046                    std::move(promise));
21047       break;
21048     }
21049     case DialogType::None:
21050     default:
21051       UNREACHABLE();
21052   }
21053 }
21054 
read_message_thread_history_on_server_impl(Dialog * d,MessageId top_thread_message_id,MessageId max_message_id)21055 void MessagesManager::read_message_thread_history_on_server_impl(Dialog *d, MessageId top_thread_message_id,
21056                                                                  MessageId max_message_id) {
21057   CHECK(d != nullptr);
21058   auto dialog_id = d->dialog_id;
21059   CHECK(dialog_id.get_type() == DialogType::Channel);
21060 
21061   const Message *m = get_message_force(d, top_thread_message_id, "read_message_thread_history_on_server_impl");
21062   if (m != nullptr) {
21063     auto message_id = m->reply_info.last_read_inbox_message_id.get_prev_server_message_id();
21064     if (message_id > max_message_id) {
21065       max_message_id = message_id;
21066     }
21067   }
21068 
21069   Promise<> promise;
21070   if (d->read_history_log_event_ids[top_thread_message_id.get()].log_event_id != 0) {
21071     d->read_history_log_event_ids[top_thread_message_id.get()].generation++;
21072     promise = PromiseCreator::lambda(
21073         [actor_id = actor_id(this), dialog_id, top_thread_message_id,
21074          generation = d->read_history_log_event_ids[top_thread_message_id.get()].generation](Result<Unit> result) {
21075           if (!G()->close_flag()) {
21076             send_closure(actor_id, &MessagesManager::on_read_history_finished, dialog_id, top_thread_message_id,
21077                          generation);
21078           }
21079         });
21080   }
21081 
21082   if (!max_message_id.is_valid() || !have_input_peer(dialog_id, AccessRights::Read)) {
21083     return promise.set_value(Unit());
21084   }
21085 
21086   LOG(INFO) << "Send read history request in thread of " << top_thread_message_id << " in " << dialog_id << " up to "
21087             << max_message_id;
21088   td_->create_handler<ReadDiscussionQuery>(std::move(promise))->send(dialog_id, top_thread_message_id, max_message_id);
21089 }
21090 
on_read_history_finished(DialogId dialog_id,MessageId top_thread_message_id,uint64 generation)21091 void MessagesManager::on_read_history_finished(DialogId dialog_id, MessageId top_thread_message_id, uint64 generation) {
21092   auto d = get_dialog(dialog_id);
21093   CHECK(d != nullptr);
21094   auto it = d->read_history_log_event_ids.find(top_thread_message_id.get());
21095   if (it == d->read_history_log_event_ids.end()) {
21096     return;
21097   }
21098   delete_log_event(it->second, generation, "read history");
21099   if (it->second.log_event_id == 0) {
21100     d->read_history_log_event_ids.erase(it);
21101   }
21102 }
21103 
21104 template <class T, class It>
get_message_history_slice(const T & begin,It it,const T & end,MessageId from_message_id,int32 offset,int32 limit)21105 vector<MessageId> MessagesManager::get_message_history_slice(const T &begin, It it, const T &end,
21106                                                              MessageId from_message_id, int32 offset, int32 limit) {
21107   int32 left_offset = -offset;
21108   int32 left_limit = limit + offset;
21109   while (left_offset > 0 && it != end) {
21110     ++it;
21111     left_offset--;
21112     left_limit++;
21113   }
21114 
21115   vector<MessageId> message_ids;
21116   while (left_limit > 0 && it != begin) {
21117     --it;
21118     left_limit--;
21119     message_ids.push_back(*it);
21120   }
21121   return message_ids;
21122 }
21123 
get_message_thread_history(DialogId dialog_id,MessageId message_id,MessageId from_message_id,int32 offset,int32 limit,int64 & random_id,Promise<Unit> && promise)21124 std::pair<DialogId, vector<MessageId>> MessagesManager::get_message_thread_history(
21125     DialogId dialog_id, MessageId message_id, MessageId from_message_id, int32 offset, int32 limit, int64 &random_id,
21126     Promise<Unit> &&promise) {
21127   if (limit <= 0) {
21128     promise.set_error(Status::Error(400, "Parameter limit must be positive"));
21129     return {};
21130   }
21131   if (limit > MAX_GET_HISTORY) {
21132     limit = MAX_GET_HISTORY;
21133   }
21134   if (offset > 0) {
21135     promise.set_error(Status::Error(400, "Parameter offset must be non-positive"));
21136     return {};
21137   }
21138   if (offset <= -MAX_GET_HISTORY) {
21139     promise.set_error(Status::Error(400, "Parameter offset must be greater than -100"));
21140     return {};
21141   }
21142   if (offset < -limit) {
21143     promise.set_error(Status::Error(400, "Parameter offset must be greater than or equal to -limit"));
21144     return {};
21145   }
21146   bool is_limit_increased = false;
21147   if (limit == -offset) {
21148     limit++;
21149     is_limit_increased = true;
21150   }
21151   CHECK(0 < limit && limit <= MAX_GET_HISTORY);
21152   CHECK(-limit < offset && offset <= 0);
21153 
21154   Dialog *d = get_dialog_force(dialog_id, "get_message_thread_history");
21155   if (d == nullptr) {
21156     promise.set_error(Status::Error(400, "Chat not found"));
21157     return {};
21158   }
21159   if (!have_input_peer(dialog_id, AccessRights::Read)) {
21160     promise.set_error(Status::Error(400, "Can't access the chat"));
21161     return {};
21162   }
21163   if (dialog_id.get_type() != DialogType::Channel) {
21164     promise.set_error(Status::Error(400, "Can't get message thread history in the chat"));
21165     return {};
21166   }
21167 
21168   if (from_message_id == MessageId() || from_message_id.get() > MessageId::max().get()) {
21169     from_message_id = MessageId::max();
21170   }
21171   if (!from_message_id.is_valid()) {
21172     promise.set_error(Status::Error(400, "Parameter from_message_id must be identifier of a chat message or 0"));
21173     return {};
21174   }
21175 
21176   FullMessageId top_thread_full_message_id;
21177   {
21178     Message *m = get_message_force(d, message_id, "get_message_thread_history 1");
21179     if (m == nullptr) {
21180       promise.set_error(Status::Error(400, "Message not found"));
21181       return {};
21182     }
21183 
21184     auto r_top_thread_full_message_id = get_top_thread_full_message_id(dialog_id, m);
21185     if (r_top_thread_full_message_id.is_error()) {
21186       promise.set_error(r_top_thread_full_message_id.move_as_error());
21187       return {};
21188     }
21189     top_thread_full_message_id = r_top_thread_full_message_id.move_as_ok();
21190 
21191     if (!top_thread_full_message_id.get_message_id().is_valid()) {
21192       CHECK(m->reply_info.is_comment);
21193       get_message_thread(
21194           dialog_id, message_id,
21195           PromiseCreator::lambda([promise = std::move(promise)](Result<MessageThreadInfo> &&result) mutable {
21196             if (result.is_error()) {
21197               promise.set_error(result.move_as_error());
21198             } else {
21199               promise.set_value(Unit());
21200             }
21201           }));
21202       return {};
21203     }
21204   }
21205 
21206   if (random_id != 0) {
21207     // request has already been sent before
21208     auto it = found_dialog_messages_.find(random_id);
21209     CHECK(it != found_dialog_messages_.end());
21210     auto result = std::move(it->second.second);
21211     found_dialog_messages_.erase(it);
21212 
21213     auto dialog_id_it = found_dialog_messages_dialog_id_.find(random_id);
21214     if (dialog_id_it != found_dialog_messages_dialog_id_.end()) {
21215       dialog_id = dialog_id_it->second;
21216       found_dialog_messages_dialog_id_.erase(dialog_id_it);
21217 
21218       d = get_dialog(dialog_id);
21219       CHECK(d != nullptr);
21220     }
21221     if (dialog_id != top_thread_full_message_id.get_dialog_id()) {
21222       promise.set_error(Status::Error(500, "Receive messages in an unexpected chat"));
21223       return {};
21224     }
21225 
21226     auto yet_unsent_it = d->yet_unsent_thread_message_ids.find(top_thread_full_message_id.get_message_id());
21227     if (yet_unsent_it != d->yet_unsent_thread_message_ids.end()) {
21228       const std::set<MessageId> &message_ids = yet_unsent_it->second;
21229       auto merge_message_ids = get_message_history_slice(message_ids.begin(), message_ids.lower_bound(from_message_id),
21230                                                          message_ids.end(), from_message_id, offset, limit);
21231       vector<MessageId> new_result(result.size() + merge_message_ids.size());
21232       std::merge(result.begin(), result.end(), merge_message_ids.begin(), merge_message_ids.end(), new_result.begin(),
21233                  std::greater<>());
21234       result = std::move(new_result);
21235     }
21236 
21237     Message *top_m = get_message_force(d, top_thread_full_message_id.get_message_id(), "get_message_thread_history 2");
21238     if (top_m != nullptr && !top_m->local_thread_message_ids.empty()) {
21239       vector<MessageId> &message_ids = top_m->local_thread_message_ids;
21240       vector<MessageId> merge_message_ids;
21241       while (true) {
21242         merge_message_ids = get_message_history_slice(
21243             message_ids.begin(), std::lower_bound(message_ids.begin(), message_ids.end(), from_message_id),
21244             message_ids.end(), from_message_id, offset, limit);
21245         bool found_deleted = false;
21246         for (auto local_message_id : merge_message_ids) {
21247           Message *local_m = get_message_force(d, local_message_id, "get_message_thread_history 3");
21248           if (local_m == nullptr) {
21249             auto local_it = std::lower_bound(message_ids.begin(), message_ids.end(), local_message_id);
21250             CHECK(local_it != message_ids.end() && *local_it == local_message_id);
21251             message_ids.erase(local_it);
21252             found_deleted = true;
21253           }
21254         }
21255         if (!found_deleted) {
21256           break;
21257         }
21258         on_message_changed(d, top_m, false, "get_message_thread_history");
21259       }
21260       vector<MessageId> new_result(result.size() + merge_message_ids.size());
21261       std::merge(result.begin(), result.end(), merge_message_ids.begin(), merge_message_ids.end(), new_result.begin(),
21262                  std::greater<>());
21263       result = std::move(new_result);
21264     }
21265 
21266     if (is_limit_increased) {
21267       limit--;
21268     }
21269 
21270     std::reverse(result.begin(), result.end());
21271     result = get_message_history_slice(result.begin(), std::lower_bound(result.begin(), result.end(), from_message_id),
21272                                        result.end(), from_message_id, offset, limit);
21273 
21274     LOG(INFO) << "Return " << result.size() << " messages in result to getMessageThreadHistory";
21275 
21276     promise.set_value(Unit());
21277     return {dialog_id, std::move(result)};
21278   }
21279 
21280   do {
21281     random_id = Random::secure_int64();
21282   } while (random_id == 0 || found_dialog_messages_.find(random_id) != found_dialog_messages_.end());
21283   found_dialog_messages_[random_id];  // reserve place for result
21284 
21285   td_->create_handler<SearchMessagesQuery>(std::move(promise))
21286       ->send(dialog_id, string(), DialogId(), from_message_id.get_next_server_message_id(), offset, limit,
21287              MessageSearchFilter::Empty, message_id, random_id);
21288   return {};
21289 }
21290 
get_dialog_message_calendar(DialogId dialog_id,MessageId from_message_id,MessageSearchFilter filter,int64 & random_id,bool use_db,Promise<Unit> && promise)21291 td_api::object_ptr<td_api::messageCalendar> MessagesManager::get_dialog_message_calendar(DialogId dialog_id,
21292                                                                                          MessageId from_message_id,
21293                                                                                          MessageSearchFilter filter,
21294                                                                                          int64 &random_id, bool use_db,
21295                                                                                          Promise<Unit> &&promise) {
21296   if (random_id != 0) {
21297     // request has already been sent before
21298     auto it = found_dialog_message_calendars_.find(random_id);
21299     if (it != found_dialog_message_calendars_.end()) {
21300       auto result = std::move(it->second);
21301       found_dialog_message_calendars_.erase(it);
21302       promise.set_value(Unit());
21303       return result;
21304     }
21305     random_id = 0;
21306   }
21307   LOG(INFO) << "Get message calendar in " << dialog_id << " filtered by " << filter << " from " << from_message_id;
21308 
21309   if (from_message_id.get() > MessageId::max().get()) {
21310     from_message_id = MessageId::max();
21311   }
21312 
21313   if (!from_message_id.is_valid() && from_message_id != MessageId()) {
21314     promise.set_error(Status::Error(400, "Parameter from_message_id must be identifier of a chat message or 0"));
21315     return {};
21316   }
21317   from_message_id = from_message_id.get_next_server_message_id();
21318 
21319   const Dialog *d = get_dialog_force(dialog_id, "get_dialog_message_calendar");
21320   if (d == nullptr) {
21321     promise.set_error(Status::Error(400, "Chat not found"));
21322     return {};
21323   }
21324   if (!have_input_peer(dialog_id, AccessRights::Read)) {
21325     promise.set_error(Status::Error(400, "Can't access the chat"));
21326     return {};
21327   }
21328 
21329   do {
21330     random_id = Random::secure_int64();
21331   } while (random_id == 0 || found_dialog_message_calendars_.find(random_id) != found_dialog_message_calendars_.end());
21332   found_dialog_message_calendars_[random_id];  // reserve place for result
21333 
21334   if (filter == MessageSearchFilter::Empty || filter == MessageSearchFilter::Call ||
21335       filter == MessageSearchFilter::MissedCall || filter == MessageSearchFilter::Mention ||
21336       filter == MessageSearchFilter::UnreadMention) {
21337     promise.set_error(Status::Error(400, "The filter is not supported"));
21338     return {};
21339   }
21340 
21341   // Trying to use database
21342   if (use_db && G()->parameters().use_message_db) {
21343     MessageId first_db_message_id = get_first_database_message_id_by_index(d, filter);
21344     int32 message_count = d->message_count_by_index[message_search_filter_index(filter)];
21345     auto fixed_from_message_id = from_message_id;
21346     if (fixed_from_message_id == MessageId()) {
21347       fixed_from_message_id = MessageId::max();
21348     }
21349     LOG(INFO) << "Get message calendar in " << dialog_id << " from " << fixed_from_message_id << ", have up to "
21350               << first_db_message_id << ", message_count = " << message_count;
21351     if (first_db_message_id < fixed_from_message_id && message_count != -1) {
21352       LOG(INFO) << "Get message calendar from database in " << dialog_id << " from " << fixed_from_message_id;
21353       auto new_promise =
21354           PromiseCreator::lambda([random_id, dialog_id, fixed_from_message_id, first_db_message_id, filter,
21355                                   promise = std::move(promise)](Result<MessagesDbCalendar> r_calendar) mutable {
21356             send_closure(G()->messages_manager(), &MessagesManager::on_get_message_calendar_from_database, random_id,
21357                          dialog_id, fixed_from_message_id, first_db_message_id, filter, std::move(r_calendar),
21358                          std::move(promise));
21359           });
21360       MessagesDbDialogCalendarQuery db_query;
21361       db_query.dialog_id = dialog_id;
21362       db_query.filter = filter;
21363       db_query.from_message_id = fixed_from_message_id;
21364       db_query.tz_offset = static_cast<int32>(G()->shared_config().get_option_integer("utc_time_offset"));
21365       G()->td_db()->get_messages_db_async()->get_dialog_message_calendar(db_query, std::move(new_promise));
21366       return {};
21367     }
21368   }
21369   if (filter == MessageSearchFilter::FailedToSend) {
21370     promise.set_value(Unit());
21371     return {};
21372   }
21373 
21374   LOG(DEBUG) << "Get message calendar from server in " << dialog_id << " from " << from_message_id;
21375 
21376   switch (dialog_id.get_type()) {
21377     case DialogType::None:
21378     case DialogType::User:
21379     case DialogType::Chat:
21380     case DialogType::Channel:
21381       td_->create_handler<GetSearchResultCalendarQuery>(std::move(promise))
21382           ->send(dialog_id, from_message_id, filter, random_id);
21383       break;
21384     case DialogType::SecretChat:
21385       promise.set_value(Unit());
21386       break;
21387     default:
21388       UNREACHABLE();
21389       promise.set_error(Status::Error(500, "Search messages is not supported"));
21390   }
21391   return {};
21392 }
21393 
on_get_message_calendar_from_database(int64 random_id,DialogId dialog_id,MessageId from_message_id,MessageId first_db_message_id,MessageSearchFilter filter,Result<MessagesDbCalendar> r_calendar,Promise<Unit> promise)21394 void MessagesManager::on_get_message_calendar_from_database(int64 random_id, DialogId dialog_id,
21395                                                             MessageId from_message_id, MessageId first_db_message_id,
21396                                                             MessageSearchFilter filter,
21397                                                             Result<MessagesDbCalendar> r_calendar,
21398                                                             Promise<Unit> promise) {
21399   TRY_STATUS_PROMISE(promise, G()->close_status());
21400 
21401   if (r_calendar.is_error()) {
21402     LOG(ERROR) << "Failed to get message calendar from the database: " << r_calendar.error();
21403     if (first_db_message_id != MessageId::min() && dialog_id.get_type() != DialogType::SecretChat &&
21404         filter != MessageSearchFilter::FailedToSend) {
21405       found_dialog_message_calendars_.erase(random_id);
21406     }
21407     return promise.set_value(Unit());
21408   }
21409   CHECK(!from_message_id.is_scheduled());
21410   CHECK(!first_db_message_id.is_scheduled());
21411 
21412   auto calendar = r_calendar.move_as_ok();
21413 
21414   Dialog *d = get_dialog(dialog_id);
21415   CHECK(d != nullptr);
21416 
21417   auto it = found_dialog_message_calendars_.find(random_id);
21418   CHECK(it != found_dialog_message_calendars_.end());
21419   CHECK(it->second == nullptr);
21420 
21421   vector<std::pair<MessageId, int32>> periods;
21422   periods.reserve(calendar.messages.size());
21423   for (size_t i = 0; i < calendar.messages.size(); i++) {
21424     auto m = on_get_message_from_database(d, calendar.messages[i], false, "on_get_message_calendar_from_database");
21425     if (m != nullptr && first_db_message_id <= m->message_id) {
21426       CHECK(!m->message_id.is_scheduled());
21427       periods.emplace_back(m->message_id, calendar.total_counts[i]);
21428     }
21429   }
21430 
21431   if (periods.empty() && first_db_message_id != MessageId::min() && dialog_id.get_type() != DialogType::SecretChat) {
21432     LOG(INFO) << "No messages found in database";
21433     found_dialog_message_calendars_.erase(it);
21434   } else {
21435     auto total_count = d->message_count_by_index[message_search_filter_index(filter)];
21436     vector<td_api::object_ptr<td_api::messageCalendarDay>> days;
21437     for (auto &period : periods) {
21438       const auto *m = get_message(d, period.first);
21439       CHECK(m != nullptr);
21440       days.push_back(td_api::make_object<td_api::messageCalendarDay>(
21441           period.second, get_message_object(dialog_id, m, "on_get_message_calendar_from_database")));
21442     }
21443     it->second = td_api::make_object<td_api::messageCalendar>(total_count, std::move(days));
21444   }
21445   promise.set_value(Unit());
21446 }
21447 
search_dialog_messages(DialogId dialog_id,const string & query,const td_api::object_ptr<td_api::MessageSender> & sender,MessageId from_message_id,int32 offset,int32 limit,MessageSearchFilter filter,MessageId top_thread_message_id,int64 & random_id,bool use_db,Promise<Unit> && promise)21448 std::pair<int32, vector<MessageId>> MessagesManager::search_dialog_messages(
21449     DialogId dialog_id, const string &query, const td_api::object_ptr<td_api::MessageSender> &sender,
21450     MessageId from_message_id, int32 offset, int32 limit, MessageSearchFilter filter, MessageId top_thread_message_id,
21451     int64 &random_id, bool use_db, Promise<Unit> &&promise) {
21452   if (random_id != 0) {
21453     // request has already been sent before
21454     auto it = found_dialog_messages_.find(random_id);
21455     if (it != found_dialog_messages_.end()) {
21456       CHECK(found_dialog_messages_dialog_id_.count(random_id) == 0);
21457       auto result = std::move(it->second);
21458       found_dialog_messages_.erase(it);
21459       promise.set_value(Unit());
21460       return result;
21461     }
21462     random_id = 0;
21463   }
21464   LOG(INFO) << "Search messages with query \"" << query << "\" in " << dialog_id << " sent by "
21465             << oneline(to_string(sender)) << " in thread of " << top_thread_message_id << " filtered by " << filter
21466             << " from " << from_message_id << " with offset " << offset << " and limit " << limit;
21467 
21468   std::pair<int32, vector<MessageId>> result;
21469   if (limit <= 0) {
21470     promise.set_error(Status::Error(400, "Parameter limit must be positive"));
21471     return result;
21472   }
21473   if (limit > MAX_SEARCH_MESSAGES) {
21474     limit = MAX_SEARCH_MESSAGES;
21475   }
21476   if (limit <= -offset) {
21477     promise.set_error(Status::Error(400, "Parameter limit must be greater than -offset"));
21478     return result;
21479   }
21480   if (offset > 0) {
21481     promise.set_error(Status::Error(400, "Parameter offset must be non-positive"));
21482     return result;
21483   }
21484 
21485   if (from_message_id.get() > MessageId::max().get()) {
21486     from_message_id = MessageId::max();
21487   }
21488 
21489   if (!from_message_id.is_valid() && from_message_id != MessageId()) {
21490     promise.set_error(Status::Error(400, "Parameter from_message_id must be identifier of a chat message or 0"));
21491     return result;
21492   }
21493   from_message_id = from_message_id.get_next_server_message_id();
21494 
21495   const Dialog *d = get_dialog_force(dialog_id, "search_dialog_messages");
21496   if (d == nullptr) {
21497     promise.set_error(Status::Error(400, "Chat not found"));
21498     return result;
21499   }
21500   if (!have_input_peer(dialog_id, AccessRights::Read)) {
21501     promise.set_error(Status::Error(400, "Can't access the chat"));
21502     return result;
21503   }
21504 
21505   auto r_sender_dialog_id = get_message_sender_dialog_id(td_, sender, true, true);
21506   if (r_sender_dialog_id.is_error()) {
21507     promise.set_error(r_sender_dialog_id.move_as_error());
21508     return result;
21509   }
21510   auto sender_dialog_id = r_sender_dialog_id.move_as_ok();
21511   if (sender_dialog_id != DialogId() && !have_input_peer(sender_dialog_id, AccessRights::Know)) {
21512     promise.set_error(Status::Error(400, "Invalid message sender specified"));
21513     return result;
21514   }
21515   if (sender_dialog_id == dialog_id && is_broadcast_channel(dialog_id)) {
21516     sender_dialog_id = DialogId();
21517   }
21518 
21519   if (filter == MessageSearchFilter::FailedToSend && sender_dialog_id.is_valid()) {
21520     if (sender_dialog_id != get_my_dialog_id()) {
21521       promise.set_value(Unit());
21522       return result;
21523     }
21524     sender_dialog_id = DialogId();
21525   }
21526 
21527   if (top_thread_message_id != MessageId()) {
21528     if (!top_thread_message_id.is_valid() || !top_thread_message_id.is_server()) {
21529       promise.set_error(Status::Error(400, "Invalid message thread ID specified"));
21530       return result;
21531     }
21532     if (dialog_id.get_type() != DialogType::Channel || is_broadcast_channel(dialog_id)) {
21533       promise.set_error(Status::Error(400, "Can't filter by message thread ID in the chat"));
21534       return result;
21535     }
21536   }
21537 
21538   if (sender_dialog_id.get_type() == DialogType::SecretChat) {
21539     promise.set_value(Unit());
21540     return result;
21541   }
21542 
21543   do {
21544     random_id = Random::secure_int64();
21545   } while (random_id == 0 || found_dialog_messages_.find(random_id) != found_dialog_messages_.end());
21546   found_dialog_messages_[random_id];  // reserve place for result
21547 
21548   if (filter == MessageSearchFilter::UnreadMention) {
21549     if (!query.empty()) {
21550       promise.set_error(Status::Error(400, "Non-empty query is unsupported with the specified filter"));
21551       return result;
21552     }
21553     if (sender_dialog_id.is_valid()) {
21554       promise.set_error(Status::Error(400, "Filtering by sender is unsupported with the specified filter"));
21555       return result;
21556     }
21557     if (top_thread_message_id != MessageId()) {
21558       promise.set_error(Status::Error(400, "Filtering by message thread is unsupported with the specified filter"));
21559       return result;
21560     }
21561   }
21562 
21563   // Trying to use database
21564   if (use_db && query.empty() && G()->parameters().use_message_db && filter != MessageSearchFilter::Empty &&
21565       !sender_dialog_id.is_valid() && top_thread_message_id == MessageId()) {
21566     MessageId first_db_message_id = get_first_database_message_id_by_index(d, filter);
21567     int32 message_count = d->message_count_by_index[message_search_filter_index(filter)];
21568     auto fixed_from_message_id = from_message_id;
21569     if (fixed_from_message_id == MessageId()) {
21570       fixed_from_message_id = MessageId::max();
21571     }
21572     LOG(INFO) << "Search messages in " << dialog_id << " from " << fixed_from_message_id << ", have up to "
21573               << first_db_message_id << ", message_count = " << message_count;
21574     if ((first_db_message_id < fixed_from_message_id || (first_db_message_id == fixed_from_message_id && offset < 0)) &&
21575         message_count != -1) {
21576       LOG(INFO) << "Search messages in database in " << dialog_id << " from " << fixed_from_message_id
21577                 << " and with limit " << limit;
21578       auto new_promise = PromiseCreator::lambda(
21579           [random_id, dialog_id, fixed_from_message_id, first_db_message_id, filter, offset, limit,
21580            promise = std::move(promise)](Result<vector<MessagesDbDialogMessage>> r_messages) mutable {
21581             send_closure(G()->messages_manager(), &MessagesManager::on_search_dialog_messages_db_result, random_id,
21582                          dialog_id, fixed_from_message_id, first_db_message_id, filter, offset, limit,
21583                          std::move(r_messages), std::move(promise));
21584           });
21585       MessagesDbMessagesQuery db_query;
21586       db_query.dialog_id = dialog_id;
21587       db_query.filter = filter;
21588       db_query.from_message_id = fixed_from_message_id;
21589       db_query.offset = offset;
21590       db_query.limit = limit;
21591       G()->td_db()->get_messages_db_async()->get_messages(db_query, std::move(new_promise));
21592       return result;
21593     }
21594   }
21595   if (filter == MessageSearchFilter::FailedToSend) {
21596     promise.set_value(Unit());
21597     return result;
21598   }
21599 
21600   LOG(DEBUG) << "Search messages on server in " << dialog_id << " with query \"" << query << "\" from "
21601              << sender_dialog_id << " in thread of " << top_thread_message_id << " from " << from_message_id
21602              << " and with limit " << limit;
21603 
21604   switch (dialog_id.get_type()) {
21605     case DialogType::None:
21606     case DialogType::User:
21607     case DialogType::Chat:
21608     case DialogType::Channel:
21609       td_->create_handler<SearchMessagesQuery>(std::move(promise))
21610           ->send(dialog_id, query, sender_dialog_id, from_message_id, offset, limit, filter, top_thread_message_id,
21611                  random_id);
21612       break;
21613     case DialogType::SecretChat:
21614       if (filter == MessageSearchFilter::UnreadMention || filter == MessageSearchFilter::Pinned) {
21615         promise.set_value(Unit());
21616       } else {
21617         promise.set_error(Status::Error(500, "Search messages in secret chats is not supported"));
21618       }
21619       break;
21620     default:
21621       UNREACHABLE();
21622       promise.set_error(Status::Error(500, "Search messages is not supported"));
21623   }
21624   return result;
21625 }
21626 
search_call_messages(MessageId from_message_id,int32 limit,bool only_missed,int64 & random_id,bool use_db,Promise<Unit> && promise)21627 std::pair<int32, vector<FullMessageId>> MessagesManager::search_call_messages(MessageId from_message_id, int32 limit,
21628                                                                               bool only_missed, int64 &random_id,
21629                                                                               bool use_db, Promise<Unit> &&promise) {
21630   if (random_id != 0) {
21631     // request has already been sent before
21632     auto it = found_call_messages_.find(random_id);
21633     if (it != found_call_messages_.end()) {
21634       auto result = std::move(it->second);
21635       found_call_messages_.erase(it);
21636       promise.set_value(Unit());
21637       return result;
21638     }
21639     random_id = 0;
21640   }
21641   LOG(INFO) << "Search call messages from " << from_message_id << " with limit " << limit;
21642 
21643   std::pair<int32, vector<FullMessageId>> result;
21644   if (limit <= 0) {
21645     promise.set_error(Status::Error(400, "Parameter limit must be positive"));
21646     return result;
21647   }
21648   if (limit > MAX_SEARCH_MESSAGES) {
21649     limit = MAX_SEARCH_MESSAGES;
21650   }
21651 
21652   if (from_message_id.get() > MessageId::max().get()) {
21653     from_message_id = MessageId::max();
21654   }
21655 
21656   if (!from_message_id.is_valid() && from_message_id != MessageId()) {
21657     promise.set_error(Status::Error(400, "Parameter from_message_id must be identifier of a chat message or 0"));
21658     return result;
21659   }
21660   from_message_id = from_message_id.get_next_server_message_id();
21661 
21662   do {
21663     random_id = Random::secure_int64();
21664   } while (random_id == 0 || found_call_messages_.find(random_id) != found_call_messages_.end());
21665   found_call_messages_[random_id];  // reserve place for result
21666 
21667   auto filter = only_missed ? MessageSearchFilter::MissedCall : MessageSearchFilter::Call;
21668 
21669   if (use_db && G()->parameters().use_message_db) {
21670     // try to use database
21671     MessageId first_db_message_id =
21672         calls_db_state_.first_calls_database_message_id_by_index[call_message_search_filter_index(filter)];
21673     int32 message_count = calls_db_state_.message_count_by_index[call_message_search_filter_index(filter)];
21674     auto fixed_from_message_id = from_message_id;
21675     if (fixed_from_message_id == MessageId()) {
21676       fixed_from_message_id = MessageId::max();
21677     }
21678     CHECK(fixed_from_message_id.is_valid() && fixed_from_message_id.is_server());
21679     LOG(INFO) << "Search call messages from " << fixed_from_message_id << ", have up to " << first_db_message_id
21680               << ", message_count = " << message_count;
21681     if (first_db_message_id < fixed_from_message_id && message_count != -1) {
21682       LOG(INFO) << "Search messages in database from " << fixed_from_message_id << " and with limit " << limit;
21683 
21684       MessagesDbCallsQuery db_query;
21685       db_query.filter = filter;
21686       db_query.from_unique_message_id = fixed_from_message_id.get_server_message_id().get();
21687       db_query.limit = limit;
21688       G()->td_db()->get_messages_db_async()->get_calls(
21689           db_query, PromiseCreator::lambda([random_id, first_db_message_id, filter, promise = std::move(promise)](
21690                                                Result<MessagesDbCallsResult> calls_result) mutable {
21691             send_closure(G()->messages_manager(), &MessagesManager::on_messages_db_calls_result,
21692                          std::move(calls_result), random_id, first_db_message_id, filter, std::move(promise));
21693           }));
21694       return result;
21695     }
21696   }
21697 
21698   LOG(DEBUG) << "Search call messages on server from " << from_message_id << " and with limit " << limit;
21699   td_->create_handler<SearchMessagesQuery>(std::move(promise))
21700       ->send(DialogId(), "", DialogId(), from_message_id, 0, limit, filter, MessageId(), random_id);
21701   return result;
21702 }
21703 
search_dialog_recent_location_messages(DialogId dialog_id,int32 limit,Promise<td_api::object_ptr<td_api::messages>> && promise)21704 void MessagesManager::search_dialog_recent_location_messages(DialogId dialog_id, int32 limit,
21705                                                              Promise<td_api::object_ptr<td_api::messages>> &&promise) {
21706   LOG(INFO) << "Search recent location messages in " << dialog_id << " with limit " << limit;
21707 
21708   if (limit <= 0) {
21709     return promise.set_error(Status::Error(400, "Parameter limit must be positive"));
21710   }
21711   if (limit > MAX_SEARCH_MESSAGES) {
21712     limit = MAX_SEARCH_MESSAGES;
21713   }
21714 
21715   const Dialog *d = get_dialog_force(dialog_id, "search_dialog_recent_location_messages");
21716   if (d == nullptr) {
21717     return promise.set_error(Status::Error(400, "Chat not found"));
21718   }
21719 
21720   switch (dialog_id.get_type()) {
21721     case DialogType::User:
21722     case DialogType::Chat:
21723     case DialogType::Channel:
21724       return td_->create_handler<GetRecentLocationsQuery>(std::move(promise))->send(dialog_id, limit);
21725     case DialogType::SecretChat:
21726       return promise.set_value(get_messages_object(0, vector<td_api::object_ptr<td_api::message>>(), true));
21727     default:
21728       UNREACHABLE();
21729       promise.set_error(Status::Error(500, "Search messages is not supported"));
21730   }
21731 }
21732 
get_active_live_location_messages(Promise<Unit> && promise)21733 vector<FullMessageId> MessagesManager::get_active_live_location_messages(Promise<Unit> &&promise) {
21734   if (!G()->parameters().use_message_db) {
21735     are_active_live_location_messages_loaded_ = true;
21736   }
21737 
21738   if (!are_active_live_location_messages_loaded_) {
21739     load_active_live_location_messages_queries_.push_back(std::move(promise));
21740     if (load_active_live_location_messages_queries_.size() == 1u) {
21741       LOG(INFO) << "Trying to load active live location messages from database";
21742       G()->td_db()->get_sqlite_pmc()->get(
21743           "di_active_live_location_messages", PromiseCreator::lambda([](string value) {
21744             send_closure(G()->messages_manager(),
21745                          &MessagesManager::on_load_active_live_location_full_message_ids_from_database,
21746                          std::move(value));
21747           }));
21748     }
21749     return {};
21750   }
21751 
21752   promise.set_value(Unit());
21753   vector<FullMessageId> result;
21754   for (auto &full_message_id : active_live_location_full_message_ids_) {
21755     auto m = get_message(full_message_id);
21756     CHECK(m != nullptr);
21757     CHECK(m->content->get_type() == MessageContentType::LiveLocation);
21758     CHECK(!m->message_id.is_scheduled());
21759 
21760     if (m->is_failed_to_send) {
21761       continue;
21762     }
21763 
21764     auto live_period = get_message_content_live_location_period(m->content.get());
21765     if (live_period <= G()->unix_time() - m->date) {  // bool is_expired flag?
21766       // live location is expired
21767       continue;
21768     }
21769     result.push_back(full_message_id);
21770   }
21771 
21772   return result;
21773 }
21774 
on_load_active_live_location_full_message_ids_from_database(string value)21775 void MessagesManager::on_load_active_live_location_full_message_ids_from_database(string value) {
21776   if (G()->close_flag()) {
21777     return;
21778   }
21779   if (value.empty()) {
21780     LOG(INFO) << "Active live location messages aren't found in the database";
21781     on_load_active_live_location_messages_finished();
21782 
21783     if (!active_live_location_full_message_ids_.empty()) {
21784       save_active_live_locations();
21785     }
21786     return;
21787   }
21788 
21789   LOG(INFO) << "Successfully loaded active live location messages list of size " << value.size() << " from database";
21790 
21791   auto new_full_message_ids = std::move(active_live_location_full_message_ids_);
21792   vector<FullMessageId> old_full_message_ids;
21793   log_event_parse(old_full_message_ids, value).ensure();
21794 
21795   // TODO asynchronously load messages from database
21796   active_live_location_full_message_ids_.clear();
21797   for (const auto &full_message_id : old_full_message_ids) {
21798     Message *m = get_message_force(full_message_id, "on_load_active_live_location_full_message_ids_from_database");
21799     if (m != nullptr) {
21800       try_add_active_live_location(full_message_id.get_dialog_id(), m);
21801     }
21802   }
21803 
21804   for (const auto &full_message_id : new_full_message_ids) {
21805     add_active_live_location(full_message_id);
21806   }
21807 
21808   on_load_active_live_location_messages_finished();
21809 
21810   if (!new_full_message_ids.empty() || old_full_message_ids.size() != active_live_location_full_message_ids_.size()) {
21811     save_active_live_locations();
21812   }
21813 }
21814 
on_load_active_live_location_messages_finished()21815 void MessagesManager::on_load_active_live_location_messages_finished() {
21816   are_active_live_location_messages_loaded_ = true;
21817   auto promises = std::move(load_active_live_location_messages_queries_);
21818   load_active_live_location_messages_queries_.clear();
21819   for (auto &promise : promises) {
21820     promise.set_value(Unit());
21821   }
21822 }
21823 
try_add_active_live_location(DialogId dialog_id,const Message * m)21824 void MessagesManager::try_add_active_live_location(DialogId dialog_id, const Message *m) {
21825   CHECK(m != nullptr);
21826 
21827   if (td_->auth_manager_->is_bot()) {
21828     return;
21829   }
21830   if (m->content->get_type() != MessageContentType::LiveLocation || m->message_id.is_scheduled() ||
21831       m->message_id.is_local() || m->via_bot_user_id.is_valid() || m->forward_info != nullptr) {
21832     return;
21833   }
21834 
21835   auto live_period = get_message_content_live_location_period(m->content.get());
21836   if (live_period <= G()->unix_time() - m->date + 1) {  // bool is_expired flag?
21837     // live location is expired
21838     return;
21839   }
21840   add_active_live_location({dialog_id, m->message_id});
21841 }
21842 
add_active_live_location(FullMessageId full_message_id)21843 void MessagesManager::add_active_live_location(FullMessageId full_message_id) {
21844   if (td_->auth_manager_->is_bot()) {
21845     return;
21846   }
21847   if (!active_live_location_full_message_ids_.insert(full_message_id).second) {
21848     return;
21849   }
21850 
21851   // TODO add timer for live location expiration
21852 
21853   if (!G()->parameters().use_message_db) {
21854     return;
21855   }
21856 
21857   if (are_active_live_location_messages_loaded_) {
21858     save_active_live_locations();
21859   } else if (load_active_live_location_messages_queries_.empty()) {
21860     // load active live locations and save after that
21861     get_active_live_location_messages(Auto());
21862   }
21863 }
21864 
delete_active_live_location(DialogId dialog_id,const Message * m)21865 bool MessagesManager::delete_active_live_location(DialogId dialog_id, const Message *m) {
21866   CHECK(m != nullptr);
21867   return active_live_location_full_message_ids_.erase(FullMessageId{dialog_id, m->message_id}) != 0;
21868 }
21869 
save_active_live_locations()21870 void MessagesManager::save_active_live_locations() {
21871   CHECK(are_active_live_location_messages_loaded_);
21872   LOG(INFO) << "Save active live locations of size " << active_live_location_full_message_ids_.size() << " to database";
21873   if (G()->parameters().use_message_db) {
21874     G()->td_db()->get_sqlite_pmc()->set("di_active_live_location_messages",
21875                                         log_event_store(active_live_location_full_message_ids_).as_slice().str(),
21876                                         Auto());
21877   }
21878 }
21879 
on_message_live_location_viewed(Dialog * d,const Message * m)21880 void MessagesManager::on_message_live_location_viewed(Dialog *d, const Message *m) {
21881   CHECK(d != nullptr);
21882   CHECK(m != nullptr);
21883   CHECK(m->content->get_type() == MessageContentType::LiveLocation);
21884   CHECK(!m->message_id.is_scheduled());
21885 
21886   if (td_->auth_manager_->is_bot()) {
21887     // just in case
21888     return;
21889   }
21890 
21891   switch (d->dialog_id.get_type()) {
21892     case DialogType::User:
21893     case DialogType::Chat:
21894     case DialogType::Channel:
21895       // ok
21896       break;
21897     case DialogType::SecretChat:
21898       return;
21899     default:
21900       UNREACHABLE();
21901       return;
21902   }
21903   if (!d->is_opened) {
21904     return;
21905   }
21906 
21907   if (m->is_outgoing || !m->message_id.is_server() || m->via_bot_user_id.is_valid() || !m->sender_user_id.is_valid() ||
21908       td_->contacts_manager_->is_user_bot(m->sender_user_id) || m->forward_info != nullptr) {
21909     return;
21910   }
21911 
21912   auto live_period = get_message_content_live_location_period(m->content.get());
21913   if (live_period <= G()->unix_time() - m->date + 1) {
21914     // live location is expired
21915     return;
21916   }
21917 
21918   auto &live_location_task_id = d->pending_viewed_live_locations[m->message_id];
21919   if (live_location_task_id != 0) {
21920     return;
21921   }
21922 
21923   live_location_task_id = ++viewed_live_location_task_id_;
21924   auto &full_message_id = viewed_live_location_tasks_[live_location_task_id];
21925   full_message_id = FullMessageId(d->dialog_id, m->message_id);
21926   view_message_live_location_on_server_impl(live_location_task_id, full_message_id);
21927 }
21928 
view_message_live_location_on_server(int64 task_id)21929 void MessagesManager::view_message_live_location_on_server(int64 task_id) {
21930   if (G()->close_flag()) {
21931     return;
21932   }
21933 
21934   auto it = viewed_live_location_tasks_.find(task_id);
21935   if (it == viewed_live_location_tasks_.end()) {
21936     return;
21937   }
21938 
21939   auto full_message_id = it->second;
21940   Dialog *d = get_dialog(full_message_id.get_dialog_id());
21941   const Message *m = get_message_force(d, full_message_id.get_message_id(), "view_message_live_location_on_server");
21942   if (m == nullptr || get_message_content_live_location_period(m->content.get()) <= G()->unix_time() - m->date + 1) {
21943     // the message was deleted or live location is expired
21944     viewed_live_location_tasks_.erase(it);
21945     auto erased_count = d->pending_viewed_live_locations.erase(full_message_id.get_message_id());
21946     CHECK(erased_count > 0);
21947     return;
21948   }
21949 
21950   view_message_live_location_on_server_impl(task_id, full_message_id);
21951 }
21952 
view_message_live_location_on_server_impl(int64 task_id,FullMessageId full_message_id)21953 void MessagesManager::view_message_live_location_on_server_impl(int64 task_id, FullMessageId full_message_id) {
21954   auto promise = PromiseCreator::lambda([actor_id = actor_id(this), task_id](Unit result) {
21955     send_closure(actor_id, &MessagesManager::on_message_live_location_viewed_on_server, task_id);
21956   });
21957   read_message_contents_on_server(full_message_id.get_dialog_id(), {full_message_id.get_message_id()}, 0,
21958                                   std::move(promise), true);
21959 }
21960 
on_message_live_location_viewed_on_server(int64 task_id)21961 void MessagesManager::on_message_live_location_viewed_on_server(int64 task_id) {
21962   if (G()->close_flag()) {
21963     return;
21964   }
21965 
21966   auto it = viewed_live_location_tasks_.find(task_id);
21967   if (it == viewed_live_location_tasks_.end()) {
21968     return;
21969   }
21970 
21971   pending_message_live_location_view_timeout_.add_timeout_in(task_id, LIVE_LOCATION_VIEW_PERIOD);
21972 }
21973 
try_add_bot_command_message_id(DialogId dialog_id,const Message * m)21974 void MessagesManager::try_add_bot_command_message_id(DialogId dialog_id, const Message *m) {
21975   CHECK(m != nullptr);
21976   if (td_->auth_manager_->is_bot() || !is_group_dialog(dialog_id) || m->message_id.is_scheduled() ||
21977       !has_bot_commands(get_message_content_text(m->content.get()))) {
21978     return;
21979   }
21980 
21981   dialog_bot_command_message_ids_[dialog_id].message_ids.insert(m->message_id);
21982 }
21983 
delete_bot_command_message_id(DialogId dialog_id,MessageId message_id)21984 void MessagesManager::delete_bot_command_message_id(DialogId dialog_id, MessageId message_id) {
21985   if (message_id.is_scheduled()) {
21986     return;
21987   }
21988   auto it = dialog_bot_command_message_ids_.find(dialog_id);
21989   if (it == dialog_bot_command_message_ids_.end()) {
21990     return;
21991   }
21992   if (it->second.message_ids.erase(message_id) && it->second.message_ids.empty()) {
21993     dialog_bot_command_message_ids_.erase(it);
21994   }
21995 }
21996 
get_message_file_source_id(FullMessageId full_message_id)21997 FileSourceId MessagesManager::get_message_file_source_id(FullMessageId full_message_id) {
21998   if (td_->auth_manager_->is_bot()) {
21999     return FileSourceId();
22000   }
22001 
22002   auto dialog_id = full_message_id.get_dialog_id();
22003   auto message_id = full_message_id.get_message_id();
22004   if (!dialog_id.is_valid() || !(message_id.is_valid() || message_id.is_valid_scheduled()) ||
22005       dialog_id.get_type() == DialogType::SecretChat || !message_id.is_any_server()) {
22006     return FileSourceId();
22007   }
22008 
22009   auto &file_source_id = full_message_id_to_file_source_id_[full_message_id];
22010   if (!file_source_id.is_valid()) {
22011     file_source_id = td_->file_reference_manager_->create_message_file_source(full_message_id);
22012   }
22013   return file_source_id;
22014 }
22015 
add_message_file_sources(DialogId dialog_id,const Message * m)22016 void MessagesManager::add_message_file_sources(DialogId dialog_id, const Message *m) {
22017   if (td_->auth_manager_->is_bot()) {
22018     return;
22019   }
22020 
22021   if (dialog_id.get_type() != DialogType::SecretChat && m->is_content_secret) {
22022     // return;
22023   }
22024 
22025   auto file_ids = get_message_content_file_ids(m->content.get(), td_);
22026   if (file_ids.empty()) {
22027     return;
22028   }
22029 
22030   // do not create file_source_id for messages without file_ids
22031   auto file_source_id = get_message_file_source_id(FullMessageId(dialog_id, m->message_id));
22032   if (file_source_id.is_valid()) {
22033     for (auto file_id : file_ids) {
22034       td_->file_manager_->add_file_source(file_id, file_source_id);
22035     }
22036   }
22037 }
22038 
remove_message_file_sources(DialogId dialog_id,const Message * m)22039 void MessagesManager::remove_message_file_sources(DialogId dialog_id, const Message *m) {
22040   if (td_->auth_manager_->is_bot()) {
22041     return;
22042   }
22043 
22044   auto file_ids = get_message_content_file_ids(m->content.get(), td_);
22045   if (file_ids.empty()) {
22046     return;
22047   }
22048 
22049   // do not create file_source_id for messages without file_ids
22050   auto file_source_id = get_message_file_source_id(FullMessageId(dialog_id, m->message_id));
22051   if (file_source_id.is_valid()) {
22052     for (auto file_id : file_ids) {
22053       td_->file_manager_->remove_file_source(file_id, file_source_id);
22054     }
22055   }
22056 }
22057 
change_message_files(DialogId dialog_id,const Message * m,const vector<FileId> & old_file_ids)22058 void MessagesManager::change_message_files(DialogId dialog_id, const Message *m, const vector<FileId> &old_file_ids) {
22059   if (dialog_id.get_type() != DialogType::SecretChat && m->is_content_secret) {
22060     // return;
22061   }
22062 
22063   auto new_file_ids = get_message_content_file_ids(m->content.get(), td_);
22064   if (new_file_ids == old_file_ids) {
22065     return;
22066   }
22067 
22068   FullMessageId full_message_id{dialog_id, m->message_id};
22069   if (need_delete_message_files(dialog_id, m)) {
22070     for (auto file_id : old_file_ids) {
22071       if (!td::contains(new_file_ids, file_id) && need_delete_file(full_message_id, file_id)) {
22072         send_closure(G()->file_manager(), &FileManager::delete_file, file_id, Promise<>(), "change_message_files");
22073       }
22074     }
22075   }
22076 
22077   auto file_source_id = get_message_file_source_id(full_message_id);
22078   if (file_source_id.is_valid()) {
22079     td_->file_manager_->change_files_source(file_source_id, old_file_ids, new_file_ids);
22080   }
22081 }
22082 
get_first_database_message_id_by_index(const Dialog * d,MessageSearchFilter filter)22083 MessageId MessagesManager::get_first_database_message_id_by_index(const Dialog *d, MessageSearchFilter filter) {
22084   CHECK(d != nullptr);
22085   auto message_id = filter == MessageSearchFilter::Empty
22086                         ? d->first_database_message_id
22087                         : d->first_database_message_id_by_index[message_search_filter_index(filter)];
22088   CHECK(!message_id.is_scheduled());
22089   if (!message_id.is_valid()) {
22090     if (d->dialog_id.get_type() == DialogType::SecretChat) {
22091       LOG(ERROR) << "Invalid first_database_message_id_by_index in " << d->dialog_id;
22092       return MessageId::min();
22093     }
22094     return MessageId::max();
22095   }
22096   return message_id;
22097 }
22098 
on_search_dialog_messages_db_result(int64 random_id,DialogId dialog_id,MessageId from_message_id,MessageId first_db_message_id,MessageSearchFilter filter,int32 offset,int32 limit,Result<vector<MessagesDbDialogMessage>> r_messages,Promise<Unit> promise)22099 void MessagesManager::on_search_dialog_messages_db_result(int64 random_id, DialogId dialog_id,
22100                                                           MessageId from_message_id, MessageId first_db_message_id,
22101                                                           MessageSearchFilter filter, int32 offset, int32 limit,
22102                                                           Result<vector<MessagesDbDialogMessage>> r_messages,
22103                                                           Promise<Unit> promise) {
22104   TRY_STATUS_PROMISE(promise, G()->close_status());
22105 
22106   if (r_messages.is_error()) {
22107     LOG(ERROR) << "Failed to get messages from the database: " << r_messages.error();
22108     if (first_db_message_id != MessageId::min() && dialog_id.get_type() != DialogType::SecretChat &&
22109         filter != MessageSearchFilter::FailedToSend) {
22110       found_dialog_messages_.erase(random_id);
22111     }
22112     return promise.set_value(Unit());
22113   }
22114   CHECK(!from_message_id.is_scheduled());
22115   CHECK(!first_db_message_id.is_scheduled());
22116 
22117   auto messages = r_messages.move_as_ok();
22118 
22119   Dialog *d = get_dialog(dialog_id);
22120   CHECK(d != nullptr);
22121 
22122   auto it = found_dialog_messages_.find(random_id);
22123   CHECK(it != found_dialog_messages_.end());
22124   auto &res = it->second.second;
22125 
22126   res.reserve(messages.size());
22127   for (auto &message : messages) {
22128     auto m = on_get_message_from_database(d, message, false, "on_search_dialog_messages_db_result");
22129     if (m != nullptr && first_db_message_id <= m->message_id) {
22130       if (filter == MessageSearchFilter::UnreadMention && !m->contains_unread_mention) {
22131         // skip already read by d->last_read_all_mentions_message_id mentions
22132       } else {
22133         CHECK(!m->message_id.is_scheduled());
22134         res.push_back(m->message_id);
22135       }
22136     }
22137   }
22138 
22139   auto &message_count = d->message_count_by_index[message_search_filter_index(filter)];
22140   auto result_size = narrow_cast<int32>(res.size());
22141   bool from_the_end =
22142       from_message_id == MessageId::max() || (offset < 0 && (result_size == 0 || res[0] < from_message_id));
22143   if ((message_count != -1 && message_count < result_size) ||
22144       (message_count > result_size && from_the_end && first_db_message_id == MessageId::min() &&
22145        result_size < limit + offset)) {
22146     LOG(INFO) << "Fix found message count in " << dialog_id << " from " << message_count << " to " << result_size;
22147     message_count = result_size;
22148     if (filter == MessageSearchFilter::UnreadMention) {
22149       d->unread_mention_count = message_count;
22150       update_dialog_mention_notification_count(d);
22151       send_update_chat_unread_mention_count(d);
22152     }
22153     on_dialog_updated(dialog_id, "on_search_dialog_messages_db_result");
22154   }
22155   it->second.first = message_count;
22156   if (res.empty() && first_db_message_id != MessageId::min() && dialog_id.get_type() != DialogType::SecretChat) {
22157     LOG(INFO) << "No messages found in database";
22158     found_dialog_messages_.erase(it);
22159   } else {
22160     LOG(INFO) << "Found " << res.size() << " messages out of " << message_count << " in database";
22161     if (from_the_end && filter == MessageSearchFilter::Pinned) {
22162       set_dialog_last_pinned_message_id(d, res.empty() ? MessageId() : res[0]);
22163     }
22164   }
22165   promise.set_value(Unit());
22166 }
22167 
get_found_messages_object(const FoundMessages & found_messages,const char * source)22168 td_api::object_ptr<td_api::foundMessages> MessagesManager::get_found_messages_object(
22169     const FoundMessages &found_messages, const char *source) {
22170   vector<tl_object_ptr<td_api::message>> result;
22171   result.reserve(found_messages.full_message_ids.size());
22172   for (const auto &full_message_id : found_messages.full_message_ids) {
22173     auto message = get_message_object(full_message_id, source);
22174     if (message != nullptr) {
22175       result.push_back(std::move(message));
22176     }
22177   }
22178 
22179   return td_api::make_object<td_api::foundMessages>(found_messages.total_count, std::move(result),
22180                                                     found_messages.next_offset);
22181 }
22182 
offline_search_messages(DialogId dialog_id,const string & query,string offset,int32 limit,MessageSearchFilter filter,int64 & random_id,Promise<> && promise)22183 MessagesManager::FoundMessages MessagesManager::offline_search_messages(DialogId dialog_id, const string &query,
22184                                                                         string offset, int32 limit,
22185                                                                         MessageSearchFilter filter, int64 &random_id,
22186                                                                         Promise<> &&promise) {
22187   if (!G()->parameters().use_message_db) {
22188     promise.set_error(Status::Error(400, "Message database is required to search messages in secret chats"));
22189     return {};
22190   }
22191 
22192   if (random_id != 0) {
22193     // request has already been sent before
22194     auto it = found_fts_messages_.find(random_id);
22195     CHECK(it != found_fts_messages_.end());
22196     auto result = std::move(it->second);
22197     found_fts_messages_.erase(it);
22198     promise.set_value(Unit());
22199     return result;
22200   }
22201 
22202   if (query.empty()) {
22203     promise.set_value(Unit());
22204     return {};
22205   }
22206   if (dialog_id != DialogId() && !have_dialog_force(dialog_id, "offline_search_messages")) {
22207     promise.set_error(Status::Error(400, "Chat not found"));
22208     return {};
22209   }
22210   if (limit <= 0) {
22211     promise.set_error(Status::Error(400, "Limit must be positive"));
22212     return {};
22213   }
22214   if (limit > MAX_SEARCH_MESSAGES) {
22215     limit = MAX_SEARCH_MESSAGES;
22216   }
22217 
22218   MessagesDbFtsQuery fts_query;
22219   fts_query.query = query;
22220   fts_query.dialog_id = dialog_id;
22221   fts_query.filter = filter;
22222   if (!offset.empty()) {
22223     auto r_from_search_id = to_integer_safe<int64>(offset);
22224     if (r_from_search_id.is_error()) {
22225       promise.set_error(Status::Error(400, "Invalid offset specified"));
22226       return {};
22227     }
22228     fts_query.from_search_id = r_from_search_id.ok();
22229   }
22230   fts_query.limit = limit;
22231 
22232   do {
22233     random_id = Random::secure_int64();
22234   } while (random_id == 0 || found_fts_messages_.find(random_id) != found_fts_messages_.end());
22235   found_fts_messages_[random_id];  // reserve place for result
22236 
22237   G()->td_db()->get_messages_db_async()->get_messages_fts(
22238       std::move(fts_query),
22239       PromiseCreator::lambda([random_id, offset = std::move(offset), limit,
22240                               promise = std::move(promise)](Result<MessagesDbFtsResult> fts_result) mutable {
22241         send_closure(G()->messages_manager(), &MessagesManager::on_messages_db_fts_result, std::move(fts_result),
22242                      std::move(offset), limit, random_id, std::move(promise));
22243       }));
22244 
22245   return {};
22246 }
22247 
on_messages_db_fts_result(Result<MessagesDbFtsResult> result,string offset,int32 limit,int64 random_id,Promise<Unit> && promise)22248 void MessagesManager::on_messages_db_fts_result(Result<MessagesDbFtsResult> result, string offset, int32 limit,
22249                                                 int64 random_id, Promise<Unit> &&promise) {
22250   if (G()->close_flag()) {
22251     result = Global::request_aborted_error();
22252   }
22253   if (result.is_error()) {
22254     found_fts_messages_.erase(random_id);
22255     return promise.set_error(result.move_as_error());
22256   }
22257   auto fts_result = result.move_as_ok();
22258 
22259   auto it = found_fts_messages_.find(random_id);
22260   CHECK(it != found_fts_messages_.end());
22261   auto &res = it->second.full_message_ids;
22262 
22263   res.reserve(fts_result.messages.size());
22264   for (auto &message : fts_result.messages) {
22265     auto m = on_get_message_from_database(message, false, "on_messages_db_fts_result");
22266     if (m != nullptr) {
22267       res.emplace_back(message.dialog_id, m->message_id);
22268     }
22269   }
22270 
22271   it->second.next_offset = fts_result.next_search_id <= 1 ? string() : to_string(fts_result.next_search_id);
22272   it->second.total_count = offset.empty() && fts_result.messages.size() < static_cast<size_t>(limit)
22273                                ? static_cast<int32>(fts_result.messages.size())
22274                                : -1;
22275 
22276   promise.set_value(Unit());
22277 }
22278 
on_messages_db_calls_result(Result<MessagesDbCallsResult> result,int64 random_id,MessageId first_db_message_id,MessageSearchFilter filter,Promise<> && promise)22279 void MessagesManager::on_messages_db_calls_result(Result<MessagesDbCallsResult> result, int64 random_id,
22280                                                   MessageId first_db_message_id, MessageSearchFilter filter,
22281                                                   Promise<> &&promise) {
22282   CHECK(!first_db_message_id.is_scheduled());
22283   if (G()->close_flag()) {
22284     result = Global::request_aborted_error();
22285   }
22286   if (result.is_error()) {
22287     found_call_messages_.erase(random_id);
22288     return promise.set_error(result.move_as_error());
22289   }
22290   auto calls_result = result.move_as_ok();
22291 
22292   auto it = found_call_messages_.find(random_id);
22293   CHECK(it != found_call_messages_.end());
22294   auto &res = it->second.second;
22295 
22296   res.reserve(calls_result.messages.size());
22297   for (auto &message : calls_result.messages) {
22298     auto m = on_get_message_from_database(message, false, "on_messages_db_calls_result");
22299 
22300     if (m != nullptr && first_db_message_id <= m->message_id) {
22301       res.emplace_back(message.dialog_id, m->message_id);
22302     }
22303   }
22304   it->second.first = calls_db_state_.message_count_by_index[call_message_search_filter_index(filter)];
22305 
22306   if (res.empty() && first_db_message_id != MessageId::min()) {
22307     LOG(INFO) << "No messages found in database";
22308     found_call_messages_.erase(it);
22309   }
22310 
22311   promise.set_value(Unit());
22312 }
22313 
search_messages(FolderId folder_id,bool ignore_folder_id,const string & query,int32 offset_date,DialogId offset_dialog_id,MessageId offset_message_id,int32 limit,MessageSearchFilter filter,int32 min_date,int32 max_date,int64 & random_id,Promise<Unit> && promise)22314 std::pair<int32, vector<FullMessageId>> MessagesManager::search_messages(
22315     FolderId folder_id, bool ignore_folder_id, const string &query, int32 offset_date, DialogId offset_dialog_id,
22316     MessageId offset_message_id, int32 limit, MessageSearchFilter filter, int32 min_date, int32 max_date,
22317     int64 &random_id, Promise<Unit> &&promise) {
22318   if (random_id != 0) {
22319     // request has already been sent before
22320     auto it = found_messages_.find(random_id);
22321     CHECK(it != found_messages_.end());
22322     auto result = std::move(it->second);
22323     found_messages_.erase(it);
22324     promise.set_value(Unit());
22325     return result;
22326   }
22327 
22328   if (limit <= 0) {
22329     promise.set_error(Status::Error(400, "Parameter limit must be positive"));
22330     return {};
22331   }
22332   if (limit > MAX_SEARCH_MESSAGES) {
22333     limit = MAX_SEARCH_MESSAGES;
22334   }
22335 
22336   if (offset_date <= 0) {
22337     offset_date = std::numeric_limits<int32>::max();
22338   }
22339   if (!offset_message_id.is_valid()) {
22340     if (offset_message_id.is_valid_scheduled()) {
22341       promise.set_error(Status::Error(400, "Parameter offset_message_id can't be a scheduled message identifier"));
22342       return {};
22343     }
22344     offset_message_id = MessageId();
22345   }
22346   if (offset_message_id != MessageId() && !offset_message_id.is_server()) {
22347     promise.set_error(
22348         Status::Error(400, "Parameter offset_message_id must be identifier of the last found message or 0"));
22349     return {};
22350   }
22351 
22352   if (filter == MessageSearchFilter::Call || filter == MessageSearchFilter::MissedCall ||
22353       filter == MessageSearchFilter::Mention || filter == MessageSearchFilter::UnreadMention ||
22354       filter == MessageSearchFilter::FailedToSend || filter == MessageSearchFilter::Pinned) {
22355     promise.set_error(Status::Error(400, "The filter is not supported"));
22356     return {};
22357   }
22358 
22359   if (query.empty() && filter == MessageSearchFilter::Empty) {
22360     promise.set_value(Unit());
22361     return {};
22362   }
22363 
22364   do {
22365     random_id = Random::secure_int64();
22366   } while (random_id == 0 || found_messages_.find(random_id) != found_messages_.end());
22367   found_messages_[random_id];  // reserve place for result
22368 
22369   LOG(DEBUG) << "Search all messages filtered by " << filter << " with query = \"" << query << "\" from date "
22370              << offset_date << ", " << offset_dialog_id << ", " << offset_message_id << " and limit " << limit;
22371 
22372   td_->create_handler<SearchMessagesGlobalQuery>(std::move(promise))
22373       ->send(folder_id, ignore_folder_id, query, offset_date, offset_dialog_id, offset_message_id, limit, filter,
22374              min_date, max_date, random_id);
22375   return {};
22376 }
22377 
get_dialog_message_by_date(DialogId dialog_id,int32 date,Promise<Unit> && promise)22378 int64 MessagesManager::get_dialog_message_by_date(DialogId dialog_id, int32 date, Promise<Unit> &&promise) {
22379   Dialog *d = get_dialog_force(dialog_id, "get_dialog_message_by_date");
22380   if (d == nullptr) {
22381     promise.set_error(Status::Error(400, "Chat not found"));
22382     return 0;
22383   }
22384 
22385   if (!have_input_peer(dialog_id, AccessRights::Read)) {
22386     promise.set_error(Status::Error(400, "Can't access the chat"));
22387     return 0;
22388   }
22389 
22390   if (date <= 0) {
22391     date = 1;
22392   }
22393 
22394   int64 random_id = 0;
22395   do {
22396     random_id = Random::secure_int64();
22397   } while (random_id == 0 ||
22398            get_dialog_message_by_date_results_.find(random_id) != get_dialog_message_by_date_results_.end());
22399   get_dialog_message_by_date_results_[random_id];  // reserve place for result
22400 
22401   auto message_id = find_message_by_date(d->messages.get(), date);
22402   if (message_id.is_valid() && (message_id == d->last_message_id || get_message(d, message_id)->have_next)) {
22403     get_dialog_message_by_date_results_[random_id] = {dialog_id, message_id};
22404     promise.set_value(Unit());
22405     return random_id;
22406   }
22407 
22408   if (G()->parameters().use_message_db && d->last_database_message_id != MessageId()) {
22409     CHECK(d->first_database_message_id != MessageId());
22410     G()->td_db()->get_messages_db_async()->get_dialog_message_by_date(
22411         dialog_id, d->first_database_message_id, d->last_database_message_id, date,
22412         PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, date, random_id,
22413                                 promise = std::move(promise)](Result<MessagesDbDialogMessage> result) mutable {
22414           send_closure(actor_id, &MessagesManager::on_get_dialog_message_by_date_from_database, dialog_id, date,
22415                        random_id, std::move(result), std::move(promise));
22416         }));
22417   } else {
22418     get_dialog_message_by_date_from_server(d, date, random_id, false, std::move(promise));
22419   }
22420   return random_id;
22421 }
22422 
run_affected_history_query_until_complete(DialogId dialog_id,AffectedHistoryQuery query,bool get_affected_messages,Promise<Unit> && promise)22423 void MessagesManager::run_affected_history_query_until_complete(DialogId dialog_id, AffectedHistoryQuery query,
22424                                                                 bool get_affected_messages, Promise<Unit> &&promise) {
22425   CHECK(!G()->close_flag());
22426   auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, query, get_affected_messages,
22427                                                promise = std::move(promise)](Result<AffectedHistory> &&result) mutable {
22428     if (result.is_error()) {
22429       return promise.set_error(result.move_as_error());
22430     }
22431 
22432     send_closure(actor_id, &MessagesManager::on_get_affected_history, dialog_id, query, get_affected_messages,
22433                  result.move_as_ok(), std::move(promise));
22434   });
22435   query(dialog_id, std::move(query_promise));
22436 }
22437 
on_get_affected_history(DialogId dialog_id,AffectedHistoryQuery query,bool get_affected_messages,AffectedHistory affected_history,Promise<Unit> && promise)22438 void MessagesManager::on_get_affected_history(DialogId dialog_id, AffectedHistoryQuery query,
22439                                               bool get_affected_messages, AffectedHistory affected_history,
22440                                               Promise<Unit> &&promise) {
22441   TRY_STATUS_PROMISE(promise, G()->close_status());
22442 
22443   if (affected_history.pts_count_ > 0) {
22444     if (get_affected_messages) {
22445       affected_history.pts_count_ = 0;
22446     }
22447     auto update_promise = affected_history.is_final_ ? std::move(promise) : Promise<Unit>();
22448     if (dialog_id.get_type() == DialogType::Channel) {
22449       add_pending_channel_update(dialog_id, make_tl_object<dummyUpdate>(), affected_history.pts_,
22450                                  affected_history.pts_count_, std::move(update_promise), "on_get_affected_history");
22451     } else {
22452       td_->updates_manager_->add_pending_pts_update(make_tl_object<dummyUpdate>(), affected_history.pts_,
22453                                                     affected_history.pts_count_, Time::now(), std::move(update_promise),
22454                                                     "on_get_affected_history");
22455     }
22456   } else if (affected_history.is_final_) {
22457     promise.set_value(Unit());
22458   }
22459 
22460   if (!affected_history.is_final_) {
22461     run_affected_history_query_until_complete(dialog_id, std::move(query), get_affected_messages, std::move(promise));
22462   }
22463 }
22464 
find_message_by_date(const Message * m,int32 date)22465 MessageId MessagesManager::find_message_by_date(const Message *m, int32 date) {
22466   if (m == nullptr) {
22467     return MessageId();
22468   }
22469 
22470   if (m->date > date) {
22471     return find_message_by_date(m->left.get(), date);
22472   }
22473 
22474   auto message_id = find_message_by_date(m->right.get(), date);
22475   if (message_id.is_valid()) {
22476     return message_id;
22477   }
22478 
22479   return m->message_id;
22480 }
22481 
find_messages_by_date(const Message * m,int32 min_date,int32 max_date,vector<MessageId> & message_ids)22482 void MessagesManager::find_messages_by_date(const Message *m, int32 min_date, int32 max_date,
22483                                             vector<MessageId> &message_ids) {
22484   if (m == nullptr) {
22485     return;
22486   }
22487 
22488   if (m->date >= min_date) {
22489     find_messages_by_date(m->left.get(), min_date, max_date, message_ids);
22490     if (m->date <= max_date) {
22491       message_ids.push_back(m->message_id);
22492     }
22493   }
22494   if (m->date <= max_date) {
22495     find_messages_by_date(m->right.get(), min_date, max_date, message_ids);
22496   }
22497 }
22498 
on_get_dialog_message_by_date_from_database(DialogId dialog_id,int32 date,int64 random_id,Result<MessagesDbDialogMessage> result,Promise<Unit> promise)22499 void MessagesManager::on_get_dialog_message_by_date_from_database(DialogId dialog_id, int32 date, int64 random_id,
22500                                                                   Result<MessagesDbDialogMessage> result,
22501                                                                   Promise<Unit> promise) {
22502   TRY_STATUS_PROMISE(promise, G()->close_status());
22503 
22504   Dialog *d = get_dialog(dialog_id);
22505   CHECK(d != nullptr);
22506   if (result.is_ok()) {
22507     Message *m = on_get_message_from_database(d, result.ok(), false, "on_get_dialog_message_by_date_from_database");
22508     if (m != nullptr) {
22509       auto message_id = find_message_by_date(d->messages.get(), date);
22510       if (!message_id.is_valid()) {
22511         LOG(ERROR) << "Failed to find " << m->message_id << " in " << dialog_id << " by date " << date;
22512         message_id = m->message_id;
22513       }
22514       get_dialog_message_by_date_results_[random_id] = {dialog_id, message_id};
22515       promise.set_value(Unit());
22516       return;
22517     }
22518     // TODO if m == nullptr, we need to just adjust it to the next non-nullptr message, not get from server
22519   }
22520 
22521   return get_dialog_message_by_date_from_server(d, date, random_id, true, std::move(promise));
22522 }
22523 
get_dialog_message_by_date_from_server(const Dialog * d,int32 date,int64 random_id,bool after_database_search,Promise<Unit> && promise)22524 void MessagesManager::get_dialog_message_by_date_from_server(const Dialog *d, int32 date, int64 random_id,
22525                                                              bool after_database_search, Promise<Unit> &&promise) {
22526   CHECK(d != nullptr);
22527   if (d->have_full_history) {
22528     // request can be always done locally/in memory. There is no need to send request to the server
22529     if (after_database_search) {
22530       return promise.set_value(Unit());
22531     }
22532 
22533     auto message_id = find_message_by_date(d->messages.get(), date);
22534     if (message_id.is_valid()) {
22535       get_dialog_message_by_date_results_[random_id] = {d->dialog_id, message_id};
22536     }
22537     promise.set_value(Unit());
22538     return;
22539   }
22540   if (d->dialog_id.get_type() == DialogType::SecretChat) {
22541     // there is no way to send request to the server
22542     return promise.set_value(Unit());
22543   }
22544 
22545   td_->create_handler<GetDialogMessageByDateQuery>(std::move(promise))->send(d->dialog_id, date, random_id);
22546 }
22547 
on_get_dialog_message_by_date_success(DialogId dialog_id,int32 date,int64 random_id,vector<tl_object_ptr<telegram_api::Message>> && messages,Promise<Unit> && promise)22548 void MessagesManager::on_get_dialog_message_by_date_success(DialogId dialog_id, int32 date, int64 random_id,
22549                                                             vector<tl_object_ptr<telegram_api::Message>> &&messages,
22550                                                             Promise<Unit> &&promise) {
22551   TRY_STATUS_PROMISE(promise, G()->close_status());
22552 
22553   auto it = get_dialog_message_by_date_results_.find(random_id);
22554   CHECK(it != get_dialog_message_by_date_results_.end());
22555   auto &result = it->second;
22556   CHECK(result == FullMessageId());
22557 
22558   for (auto &message : messages) {
22559     auto message_date = get_message_date(message);
22560     auto message_dialog_id = get_message_dialog_id(message);
22561     if (message_dialog_id != dialog_id) {
22562       LOG(ERROR) << "Receive message in wrong " << message_dialog_id << " instead of " << dialog_id;
22563       continue;
22564     }
22565     if (message_date != 0 && message_date <= date) {
22566       result = on_get_message(std::move(message), false, dialog_id.get_type() == DialogType::Channel, false, false,
22567                               false, "on_get_dialog_message_by_date_success");
22568       if (result != FullMessageId()) {
22569         const Dialog *d = get_dialog(dialog_id);
22570         CHECK(d != nullptr);
22571         auto message_id = find_message_by_date(d->messages.get(), date);
22572         if (!message_id.is_valid()) {
22573           LOG(ERROR) << "Failed to find " << result.get_message_id() << " in " << dialog_id << " by date " << date;
22574           message_id = result.get_message_id();
22575         }
22576         get_dialog_message_by_date_results_[random_id] = {dialog_id, message_id};
22577         // TODO result must be adjusted by local messages
22578         promise.set_value(Unit());
22579         return;
22580       }
22581     }
22582   }
22583   promise.set_value(Unit());
22584 }
22585 
on_get_dialog_message_by_date_fail(int64 random_id)22586 void MessagesManager::on_get_dialog_message_by_date_fail(int64 random_id) {
22587   auto erased_count = get_dialog_message_by_date_results_.erase(random_id);
22588   CHECK(erased_count > 0);
22589 }
22590 
get_dialog_message_by_date_object(int64 random_id)22591 tl_object_ptr<td_api::message> MessagesManager::get_dialog_message_by_date_object(int64 random_id) {
22592   auto it = get_dialog_message_by_date_results_.find(random_id);
22593   CHECK(it != get_dialog_message_by_date_results_.end());
22594   auto full_message_id = std::move(it->second);
22595   get_dialog_message_by_date_results_.erase(it);
22596   return get_message_object(full_message_id, "get_dialog_message_by_date_object");
22597 }
22598 
get_dialog_sparse_message_positions(DialogId dialog_id,MessageSearchFilter filter,MessageId from_message_id,int32 limit,Promise<td_api::object_ptr<td_api::messagePositions>> && promise)22599 void MessagesManager::get_dialog_sparse_message_positions(
22600     DialogId dialog_id, MessageSearchFilter filter, MessageId from_message_id, int32 limit,
22601     Promise<td_api::object_ptr<td_api::messagePositions>> &&promise) {
22602   const Dialog *d = get_dialog_force(dialog_id, "get_dialog_sparse_message_positions");
22603   if (d == nullptr) {
22604     return promise.set_error(Status::Error(400, "Chat not found"));
22605   }
22606   if (limit < 50 || limit > 2000) {  // server-side limits
22607     return promise.set_error(Status::Error(400, "Invalid limit specified"));
22608   }
22609 
22610   if (filter == MessageSearchFilter::Empty || filter == MessageSearchFilter::Call ||
22611       filter == MessageSearchFilter::MissedCall || filter == MessageSearchFilter::Mention ||
22612       filter == MessageSearchFilter::UnreadMention || filter == MessageSearchFilter::Pinned) {
22613     return promise.set_error(Status::Error(400, "The filter is not supported"));
22614   }
22615 
22616   if (from_message_id.is_scheduled()) {
22617     return promise.set_error(Status::Error(400, "Invalid from_message_id specified"));
22618   }
22619   if (!from_message_id.is_valid() || from_message_id > d->last_new_message_id) {
22620     if (d->last_new_message_id.is_valid()) {
22621       from_message_id = d->last_new_message_id.get_next_message_id(MessageType::Server);
22622     } else {
22623       from_message_id = MessageId::max();
22624     }
22625   } else {
22626     from_message_id = from_message_id.get_next_server_message_id();
22627   }
22628 
22629   if (filter == MessageSearchFilter::FailedToSend || dialog_id.get_type() == DialogType::SecretChat) {
22630     if (!G()->parameters().use_message_db) {
22631       return promise.set_error(Status::Error(400, "Unsupported without message database"));
22632     }
22633 
22634     LOG(INFO) << "Get sparse message positions from database";
22635     auto new_promise =
22636         PromiseCreator::lambda([promise = std::move(promise)](Result<MessagesDbMessagePositions> result) mutable {
22637           if (result.is_error()) {
22638             return promise.set_error(result.move_as_error());
22639           }
22640 
22641           auto positions = result.move_as_ok();
22642           promise.set_value(td_api::make_object<td_api::messagePositions>(
22643               positions.total_count, transform(positions.positions, [](const MessagesDbMessagePosition &position) {
22644                 return td_api::make_object<td_api::messagePosition>(position.position, position.message_id.get(),
22645                                                                     position.date);
22646               })));
22647         });
22648     MessagesDbGetDialogSparseMessagePositionsQuery db_query;
22649     db_query.dialog_id = dialog_id;
22650     db_query.filter = filter;
22651     db_query.from_message_id = from_message_id;
22652     db_query.limit = limit;
22653     G()->td_db()->get_messages_db_async()->get_dialog_sparse_message_positions(db_query, std::move(new_promise));
22654     return;
22655   }
22656 
22657   switch (dialog_id.get_type()) {
22658     case DialogType::User:
22659     case DialogType::Chat:
22660     case DialogType::Channel:
22661       td_->create_handler<GetSearchResultPositionsQuery>(std::move(promise))
22662           ->send(dialog_id, filter, from_message_id, limit);
22663       break;
22664     case DialogType::SecretChat:
22665     case DialogType::None:
22666     default:
22667       UNREACHABLE();
22668   }
22669 }
22670 
on_get_dialog_sparse_message_positions(DialogId dialog_id,MessageSearchFilter filter,telegram_api::object_ptr<telegram_api::messages_searchResultsPositions> positions,Promise<td_api::object_ptr<td_api::messagePositions>> && promise)22671 void MessagesManager::on_get_dialog_sparse_message_positions(
22672     DialogId dialog_id, MessageSearchFilter filter,
22673     telegram_api::object_ptr<telegram_api::messages_searchResultsPositions> positions,
22674     Promise<td_api::object_ptr<td_api::messagePositions>> &&promise) {
22675   auto message_positions = transform(
22676       positions->positions_, [](const telegram_api::object_ptr<telegram_api::searchResultPosition> &position) {
22677         return td_api::make_object<td_api::messagePosition>(
22678             position->offset_, MessageId(ServerMessageId(position->msg_id_)).get(), position->date_);
22679       });
22680   promise.set_value(td_api::make_object<td_api::messagePositions>(positions->count_, std::move(message_positions)));
22681 }
22682 
get_dialog_message_count(DialogId dialog_id,MessageSearchFilter filter,bool return_local,Promise<int32> && promise)22683 void MessagesManager::get_dialog_message_count(DialogId dialog_id, MessageSearchFilter filter, bool return_local,
22684                                                Promise<int32> &&promise) {
22685   LOG(INFO) << "Get " << (return_local ? "local " : "") << "number of messages in " << dialog_id << " filtered by "
22686             << filter;
22687 
22688   const Dialog *d = get_dialog_force(dialog_id, "get_dialog_message_count");
22689   if (d == nullptr) {
22690     return promise.set_error(Status::Error(400, "Chat not found"));
22691   }
22692 
22693   if (filter == MessageSearchFilter::Empty) {
22694     return promise.set_error(Status::Error(400, "Can't use searchMessagesFilterEmpty"));
22695   }
22696 
22697   auto dialog_type = dialog_id.get_type();
22698   int32 message_count = d->message_count_by_index[message_search_filter_index(filter)];
22699   if (message_count == -1 && filter == MessageSearchFilter::UnreadMention) {
22700     message_count = d->unread_mention_count;
22701   }
22702   if (message_count != -1 || return_local || dialog_type == DialogType::SecretChat ||
22703       filter == MessageSearchFilter::FailedToSend) {
22704     return promise.set_value(std::move(message_count));
22705   }
22706 
22707   LOG(INFO) << "Get number of messages in " << dialog_id << " filtered by " << filter << " from the server";
22708 
22709   switch (dialog_type) {
22710     case DialogType::User:
22711     case DialogType::Chat:
22712     case DialogType::Channel:
22713       td_->create_handler<GetSearchCountersQuery>(std::move(promise))->send(dialog_id, filter);
22714       break;
22715     case DialogType::None:
22716     case DialogType::SecretChat:
22717     default:
22718       UNREACHABLE();
22719   }
22720 }
22721 
preload_newer_messages(const Dialog * d,MessageId max_message_id)22722 void MessagesManager::preload_newer_messages(const Dialog *d, MessageId max_message_id) {
22723   CHECK(d != nullptr);
22724   CHECK(max_message_id.is_valid());
22725   if (td_->auth_manager_->is_bot()) {
22726     return;
22727   }
22728 
22729   MessagesConstIterator p(d, max_message_id);
22730   int32 limit = MAX_GET_HISTORY * 3 / 10;
22731   while (*p != nullptr && limit-- > 0) {
22732     ++p;
22733     if (*p) {
22734       max_message_id = (*p)->message_id;
22735     }
22736   }
22737   if (limit > 0 && (d->last_message_id == MessageId() || max_message_id < d->last_message_id)) {
22738     // need to preload some new messages
22739     LOG(INFO) << "Preloading newer after " << max_message_id;
22740     load_messages_impl(d, max_message_id, -MAX_GET_HISTORY + 1, MAX_GET_HISTORY, 3, false, Promise<Unit>());
22741   }
22742 }
22743 
preload_older_messages(const Dialog * d,MessageId min_message_id)22744 void MessagesManager::preload_older_messages(const Dialog *d, MessageId min_message_id) {
22745   CHECK(d != nullptr);
22746   CHECK(min_message_id.is_valid());
22747   if (td_->auth_manager_->is_bot()) {
22748     return;
22749   }
22750 
22751   /*
22752     if (d->first_remote_message_id == -1) {
22753       // nothing left to preload from server
22754       return;
22755     }
22756   */
22757   MessagesConstIterator p(d, min_message_id);
22758   int32 limit = MAX_GET_HISTORY * 3 / 10 + 1;
22759   while (*p != nullptr && limit-- > 0) {
22760     min_message_id = (*p)->message_id;
22761     --p;
22762   }
22763   if (limit > 0) {
22764     // need to preload some old messages
22765     LOG(INFO) << "Preloading older before " << min_message_id;
22766     load_messages_impl(d, min_message_id, 0, MAX_GET_HISTORY / 2, 3, false, Promise<Unit>());
22767   }
22768 }
22769 
parse_message(DialogId dialog_id,MessageId expected_message_id,const BufferSlice & value,bool is_scheduled)22770 unique_ptr<MessagesManager::Message> MessagesManager::parse_message(DialogId dialog_id, MessageId expected_message_id,
22771                                                                     const BufferSlice &value, bool is_scheduled) {
22772   auto m = make_unique<Message>();
22773 
22774   auto status = log_event_parse(*m, value.as_slice());
22775   bool is_message_id_valid = [&] {
22776     if (is_scheduled) {
22777       if (!expected_message_id.is_valid_scheduled()) {
22778         return false;
22779       }
22780       if (m->message_id == expected_message_id) {
22781         return true;
22782       }
22783       return m->message_id.is_valid_scheduled() && expected_message_id.is_scheduled_server() &&
22784              m->message_id.is_scheduled_server() &&
22785              m->message_id.get_scheduled_server_message_id() == expected_message_id.get_scheduled_server_message_id();
22786     } else {
22787       if (!expected_message_id.is_valid()) {
22788         return false;
22789       }
22790       return m->message_id == expected_message_id;
22791     }
22792   }();
22793   if (status.is_error() || !is_message_id_valid) {
22794     // can't happen unless the database is broken, but has been seen in the wild
22795     LOG(ERROR) << "Receive invalid message from database: " << expected_message_id << ' ' << m->message_id << ' '
22796                << status << ' ' << format::as_hex_dump<4>(value.as_slice());
22797     if (!is_scheduled && dialog_id.get_type() != DialogType::SecretChat) {
22798       // trying to repair the message
22799       if (expected_message_id.is_valid() && expected_message_id.is_server()) {
22800         get_message_from_server({dialog_id, expected_message_id}, Auto(), "parse_message");
22801       }
22802       if (m->message_id.is_valid() && m->message_id.is_server()) {
22803         get_message_from_server({dialog_id, m->message_id}, Auto(), "parse_message");
22804       }
22805     }
22806     return nullptr;
22807   }
22808 
22809   LOG(INFO) << "Loaded " << m->message_id << " in " << dialog_id << " of size " << value.size() << " from database";
22810   return m;
22811 }
22812 
on_get_history_from_database(DialogId dialog_id,MessageId from_message_id,MessageId old_last_database_message_id,int32 offset,int32 limit,bool from_the_end,bool only_local,vector<MessagesDbDialogMessage> && messages,Promise<Unit> && promise)22813 void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId from_message_id,
22814                                                    MessageId old_last_database_message_id, int32 offset, int32 limit,
22815                                                    bool from_the_end, bool only_local,
22816                                                    vector<MessagesDbDialogMessage> &&messages,
22817                                                    Promise<Unit> &&promise) {
22818   CHECK(-limit < offset && offset <= 0);
22819   CHECK(offset < 0 || from_the_end);
22820   CHECK(!from_message_id.is_scheduled());
22821   TRY_STATUS_PROMISE(promise, G()->close_status());
22822 
22823   if (!have_input_peer(dialog_id, AccessRights::Read)) {
22824     LOG(WARNING) << "Ignore result of get_history_from_database in " << dialog_id;
22825     promise.set_value(Unit());
22826     return;
22827   }
22828 
22829   auto d = get_dialog(dialog_id);
22830   CHECK(d != nullptr);
22831 
22832   LOG(INFO) << "Receive " << messages.size() << " history messages from database "
22833             << (from_the_end ? "from the end " : "") << "in " << dialog_id << " from " << from_message_id
22834             << " with offset " << offset << " and limit " << limit << ". First database message is "
22835             << d->first_database_message_id << ", last database message is " << d->last_database_message_id
22836             << ", have_full_history = " << d->have_full_history;
22837 
22838   if (old_last_database_message_id < d->last_database_message_id && old_last_database_message_id < from_message_id) {
22839     // new messages where added to the database since the request was sent
22840     // they should have been received from the database, so we must repeat the request to get them
22841     if (from_the_end) {
22842       get_history_from_the_end_impl(d, true, only_local, std::move(promise));
22843     } else {
22844       get_history_impl(d, from_message_id, offset, limit, true, only_local, std::move(promise));
22845     }
22846     return;
22847   }
22848 
22849   if (messages.empty() && from_the_end && d->messages == nullptr) {
22850     if (d->have_full_history) {
22851       set_dialog_is_empty(d, "on_get_history_from_database empty");
22852     } else if (d->last_database_message_id.is_valid()) {
22853       set_dialog_first_database_message_id(d, MessageId(), "on_get_history_from_database empty");
22854       set_dialog_last_database_message_id(d, MessageId(), "on_get_history_from_database empty");
22855     }
22856   }
22857 
22858   bool have_next = false;
22859   bool need_update = false;
22860   bool need_update_dialog_pos = false;
22861   bool added_new_message = false;
22862   MessageId first_added_message_id;
22863   MessageId last_added_message_id;
22864   Message *next_message = nullptr;
22865   Dependencies dependencies;
22866   bool is_first = true;
22867   bool had_full_history = d->have_full_history;
22868   auto debug_first_database_message_id = d->first_database_message_id;
22869   auto debug_last_message_id = d->last_message_id;
22870   auto debug_last_new_message_id = d->last_new_message_id;
22871   auto last_received_message_id = MessageId::max();
22872   size_t pos = 0;
22873   for (auto &message_slice : messages) {
22874     if (!d->first_database_message_id.is_valid() && !d->have_full_history) {
22875       break;
22876     }
22877     auto message = parse_message(dialog_id, message_slice.message_id, message_slice.data, false);
22878     if (message == nullptr) {
22879       if (d->have_full_history) {
22880         d->have_full_history = false;
22881         d->is_empty = false;  // just in case
22882         on_dialog_updated(dialog_id, "drop have_full_history in on_get_history_from_database");
22883       }
22884       break;
22885     }
22886     if (message->message_id >= last_received_message_id) {
22887       // TODO move to ERROR
22888       LOG(FATAL) << "Receive " << message->message_id << " after " << last_received_message_id
22889                  << " from database in the history of " << dialog_id << " from " << from_message_id << " with offset "
22890                  << offset << ", limit " << limit << ", from_the_end = " << from_the_end;
22891       break;
22892     }
22893     last_received_message_id = message->message_id;
22894 
22895     if (message->message_id < d->first_database_message_id) {
22896       if (d->have_full_history) {
22897         LOG(ERROR) << "Have full history in the " << dialog_id << " and receive " << message->message_id
22898                    << " from database, but first database message is " << d->first_database_message_id;
22899       } else {
22900         break;
22901       }
22902     }
22903     if (!have_next && (from_the_end || (is_first && offset < -1 && message->message_id <= from_message_id)) &&
22904         message->message_id < d->last_message_id) {
22905       // last message in the dialog must be attached to the next local message
22906       have_next = true;
22907     }
22908 
22909     message->have_previous = false;
22910     message->have_next = have_next;
22911     message->from_database = true;
22912 
22913     auto old_message = get_message(d, message->message_id);
22914     Message *m = old_message ? old_message
22915                              : add_message_to_dialog(d, std::move(message), false, &need_update,
22916                                                      &need_update_dialog_pos, "on_get_history_from_database");
22917     if (m != nullptr) {
22918       first_added_message_id = m->message_id;
22919       if (!have_next) {
22920         last_added_message_id = m->message_id;
22921       }
22922       if (old_message == nullptr) {
22923         add_message_dependencies(dependencies, m);
22924         added_new_message = true;
22925       } else if (m->message_id != from_message_id) {
22926         added_new_message = true;
22927       }
22928       if (next_message != nullptr && !next_message->have_previous) {
22929         LOG_CHECK(m->message_id < next_message->message_id)
22930             << m->message_id << ' ' << next_message->message_id << ' ' << last_received_message_id << ' ' << dialog_id
22931             << ' ' << from_message_id << ' ' << offset << ' ' << limit << ' ' << from_the_end << ' ' << only_local
22932             << ' ' << messages.size() << ' ' << debug_first_database_message_id << ' ' << last_added_message_id << ' '
22933             << added_new_message << ' ' << pos << ' ' << m << ' ' << next_message << ' ' << old_message << ' '
22934             << to_string(get_message_object(dialog_id, m, "on_get_history_from_database"))
22935             << to_string(get_message_object(dialog_id, next_message, "on_get_history_from_database"));
22936         LOG(INFO) << "Fix have_previous for " << next_message->message_id;
22937         next_message->have_previous = true;
22938         attach_message_to_previous(
22939             d, next_message->message_id,
22940             (PSLICE() << "on_get_history_from_database 1 " << m->message_id << ' ' << from_message_id << ' ' << offset
22941                       << ' ' << limit << ' ' << d->first_database_message_id << ' ' << d->have_full_history << ' '
22942                       << pos)
22943                 .c_str());
22944       }
22945 
22946       have_next = true;
22947       next_message = m;
22948     }
22949     is_first = false;
22950     pos++;
22951   }
22952   resolve_dependencies_force(td_, dependencies, "on_get_history_from_database");
22953 
22954   if (from_the_end && !last_added_message_id.is_valid() && d->first_database_message_id.is_valid() &&
22955       !d->have_full_history) {
22956     if (last_received_message_id <= d->first_database_message_id) {
22957       // database definitely has no messages from first_database_message_id to last_database_message_id; drop them
22958       set_dialog_first_database_message_id(d, MessageId(), "on_get_history_from_database 8");
22959       set_dialog_last_database_message_id(d, MessageId(), "on_get_history_from_database 9");
22960     } else {
22961       CHECK(last_received_message_id.is_valid());
22962       // if a message was received, but wasn't added, then it is likely to be already deleted
22963       // if it is less than d->last_database_message_id, then we can adjust d->last_database_message_id and
22964       // try again database search without chance to loop
22965       if (last_received_message_id < d->last_database_message_id) {
22966         set_dialog_last_database_message_id(d, last_received_message_id, "on_get_history_from_database 12");
22967 
22968         get_history_from_the_end_impl(d, true, only_local, std::move(promise));
22969         return;
22970       }
22971 
22972       if (limit > 1) {
22973         // we expected to have messages [first_database_message_id, last_database_message_id] in the database, but
22974         // received no messages or newer messages [last_received_message_id, ...], none of which can be added
22975         // first_database_message_id and last_database_message_id are very wrong, so it is better to drop them,
22976         // pretending that the database has no usable messages
22977         if (last_received_message_id == MessageId::max()) {
22978           LOG(ERROR) << "Receive no usable messages in " << dialog_id
22979                      << " from database from the end, but expected messages from " << d->last_database_message_id
22980                      << " up to " << d->first_database_message_id;
22981         } else {
22982           LOG(ERROR) << "Receive " << messages.size() << " unusable messages up to " << last_received_message_id
22983                      << " in " << dialog_id << " from database from the end, but expected messages from "
22984                      << d->last_database_message_id << " up to " << d->first_database_message_id;
22985         }
22986         set_dialog_first_database_message_id(d, MessageId(), "on_get_history_from_database 13");
22987         set_dialog_last_database_message_id(d, MessageId(), "on_get_history_from_database 14");
22988       }
22989     }
22990   }
22991 
22992   if (!added_new_message && !only_local && dialog_id.get_type() != DialogType::SecretChat) {
22993     if (from_the_end) {
22994       from_message_id = MessageId();
22995     }
22996     load_messages_impl(d, from_message_id, offset, limit, 1, false, std::move(promise));
22997     return;
22998   }
22999 
23000   if (from_the_end && last_added_message_id.is_valid()) {
23001     // CHECK(d->first_database_message_id.is_valid());
23002     // CHECK(last_added_message_id >= d->first_database_message_id);
23003     if ((had_full_history || d->have_full_history) && !d->last_new_message_id.is_valid() &&
23004         (last_added_message_id.is_server() || d->dialog_id.get_type() == DialogType::SecretChat)) {
23005       LOG(ERROR) << "Trying to hard fix " << d->dialog_id << " last new message to " << last_added_message_id
23006                  << " from on_get_history_from_database 2";
23007       d->last_new_message_id = last_added_message_id;
23008       on_dialog_updated(d->dialog_id, "on_get_history_from_database 3");
23009     }
23010     if (last_added_message_id > d->last_message_id && d->last_new_message_id.is_valid()) {
23011       set_dialog_last_message_id(d, last_added_message_id, "on_get_history_from_database 4");
23012       need_update_dialog_pos = true;
23013     }
23014     if (last_added_message_id != d->last_database_message_id && d->last_new_message_id.is_valid()) {
23015       auto debug_last_database_message_id = d->last_database_message_id;
23016       set_dialog_last_database_message_id(d, last_added_message_id, "on_get_history_from_database 5");
23017       if (last_added_message_id < d->first_database_message_id || !d->first_database_message_id.is_valid()) {
23018         CHECK(next_message != nullptr);
23019         LOG_CHECK(had_full_history || d->have_full_history)
23020             << had_full_history << ' ' << d->have_full_history << ' ' << next_message->message_id << ' '
23021             << last_added_message_id << ' ' << d->first_database_message_id << ' ' << debug_first_database_message_id
23022             << ' ' << d->last_database_message_id << ' ' << debug_last_database_message_id << ' ' << dialog_id << ' '
23023             << d->last_new_message_id << ' ' << debug_last_new_message_id << ' ' << d->last_message_id << ' '
23024             << debug_last_message_id;
23025         CHECK(next_message->message_id <= d->last_database_message_id);
23026         LOG(ERROR) << "Fix first database message in " << dialog_id << " from " << d->first_database_message_id
23027                    << " to " << next_message->message_id;
23028         set_dialog_first_database_message_id(d, next_message->message_id, "on_get_history_from_database 6");
23029       }
23030     }
23031   }
23032   if (first_added_message_id.is_valid() && first_added_message_id != d->first_database_message_id &&
23033       last_received_message_id < d->first_database_message_id && d->last_new_message_id.is_valid() &&
23034       !d->have_full_history) {
23035     CHECK(first_added_message_id > d->first_database_message_id);
23036     set_dialog_first_database_message_id(d, first_added_message_id, "on_get_history_from_database 10");
23037     if (d->last_database_message_id < d->first_database_message_id) {
23038       set_dialog_last_database_message_id(d, d->first_database_message_id, "on_get_history_from_database 11");
23039     }
23040   }
23041 
23042   if (need_update_dialog_pos) {
23043     send_update_chat_last_message(d, "on_get_history_from_database 7");
23044   }
23045 
23046   promise.set_value(Unit());
23047 }
23048 
get_history_from_the_end(DialogId dialog_id,bool from_database,bool only_local,Promise<Unit> && promise)23049 void MessagesManager::get_history_from_the_end(DialogId dialog_id, bool from_database, bool only_local,
23050                                                Promise<Unit> &&promise) {
23051   get_history_from_the_end_impl(get_dialog(dialog_id), from_database, only_local, std::move(promise));
23052 }
23053 
get_history_from_the_end_impl(const Dialog * d,bool from_database,bool only_local,Promise<Unit> && promise)23054 void MessagesManager::get_history_from_the_end_impl(const Dialog *d, bool from_database, bool only_local,
23055                                                     Promise<Unit> &&promise) {
23056   CHECK(d != nullptr);
23057   TRY_STATUS_PROMISE(promise, G()->close_status());
23058 
23059   auto dialog_id = d->dialog_id;
23060   if (!have_input_peer(dialog_id, AccessRights::Read)) {
23061     // can't get history in dialogs without read access
23062     return promise.set_value(Unit());
23063   }
23064   if (!d->first_database_message_id.is_valid() && !d->have_full_history) {
23065     from_database = false;
23066   }
23067   int32 limit = MAX_GET_HISTORY;
23068   if (from_database && G()->parameters().use_message_db) {
23069     if (!promise) {
23070       // repair last database message ID
23071       limit = 10;
23072     }
23073     LOG(INFO) << "Get history from the end of " << dialog_id << " from database";
23074     MessagesDbMessagesQuery db_query;
23075     db_query.dialog_id = dialog_id;
23076     db_query.from_message_id = MessageId::max();
23077     db_query.limit = limit;
23078     G()->td_db()->get_messages_db_async()->get_messages(
23079         db_query, PromiseCreator::lambda([dialog_id, old_last_database_message_id = d->last_database_message_id,
23080                                           only_local, limit, actor_id = actor_id(this), promise = std::move(promise)](
23081                                              vector<MessagesDbDialogMessage> messages) mutable {
23082           send_closure(actor_id, &MessagesManager::on_get_history_from_database, dialog_id, MessageId::max(),
23083                        old_last_database_message_id, 0, limit, true, only_local, std::move(messages),
23084                        std::move(promise));
23085         }));
23086   } else {
23087     if (only_local || dialog_id.get_type() == DialogType::SecretChat || d->last_message_id.is_valid()) {
23088       // if last message is known, there are no reasons to get message history from server from the end
23089       promise.set_value(Unit());
23090       return;
23091     }
23092     if (!promise && !G()->parameters().use_message_db) {
23093       // repair last message ID
23094       limit = 10;
23095     }
23096 
23097     LOG(INFO) << "Get history from the end of " << dialog_id << " from server";
23098     td_->create_handler<GetHistoryQuery>(std::move(promise))
23099         ->send_get_from_the_end(dialog_id, d->last_new_message_id, limit);
23100   }
23101 }
23102 
get_history(DialogId dialog_id,MessageId from_message_id,int32 offset,int32 limit,bool from_database,bool only_local,Promise<Unit> && promise)23103 void MessagesManager::get_history(DialogId dialog_id, MessageId from_message_id, int32 offset, int32 limit,
23104                                   bool from_database, bool only_local, Promise<Unit> &&promise) {
23105   get_history_impl(get_dialog(dialog_id), from_message_id, offset, limit, from_database, only_local,
23106                    std::move(promise));
23107 }
23108 
get_history_impl(const Dialog * d,MessageId from_message_id,int32 offset,int32 limit,bool from_database,bool only_local,Promise<Unit> && promise)23109 void MessagesManager::get_history_impl(const Dialog *d, MessageId from_message_id, int32 offset, int32 limit,
23110                                        bool from_database, bool only_local, Promise<Unit> &&promise) {
23111   CHECK(d != nullptr);
23112   CHECK(from_message_id.is_valid());
23113   TRY_STATUS_PROMISE(promise, G()->close_status());
23114 
23115   auto dialog_id = d->dialog_id;
23116   if (!have_input_peer(dialog_id, AccessRights::Read)) {
23117     // can't get history in dialogs without read access
23118     return promise.set_value(Unit());
23119   }
23120   if ((!d->first_database_message_id.is_valid() || from_message_id <= d->first_database_message_id) &&
23121       !d->have_full_history) {
23122     from_database = false;
23123   }
23124   if (from_database && G()->parameters().use_message_db) {
23125     LOG(INFO) << "Get history in " << dialog_id << " from " << from_message_id << " with offset " << offset
23126               << " and limit " << limit << " from database";
23127     MessagesDbMessagesQuery db_query;
23128     db_query.dialog_id = dialog_id;
23129     db_query.from_message_id = from_message_id;
23130     db_query.offset = offset;
23131     db_query.limit = limit;
23132     G()->td_db()->get_messages_db_async()->get_messages(
23133         db_query,
23134         PromiseCreator::lambda([dialog_id, from_message_id, old_last_database_message_id = d->last_database_message_id,
23135                                 offset, limit, only_local, actor_id = actor_id(this),
23136                                 promise = std::move(promise)](vector<MessagesDbDialogMessage> messages) mutable {
23137           send_closure(actor_id, &MessagesManager::on_get_history_from_database, dialog_id, from_message_id,
23138                        old_last_database_message_id, offset, limit, false, only_local, std::move(messages),
23139                        std::move(promise));
23140         }));
23141   } else {
23142     if (only_local || dialog_id.get_type() == DialogType::SecretChat) {
23143       return promise.set_value(Unit());
23144     }
23145 
23146     LOG(INFO) << "Get history in " << dialog_id << " from " << from_message_id << " with offset " << offset
23147               << " and limit " << limit << " from server";
23148     td_->create_handler<GetHistoryQuery>(std::move(promise))
23149         ->send(dialog_id, from_message_id.get_next_server_message_id(), d->last_new_message_id, offset, limit);
23150   }
23151 }
23152 
load_messages(DialogId dialog_id,MessageId from_message_id,int32 offset,int32 limit,int left_tries,bool only_local,Promise<Unit> && promise)23153 void MessagesManager::load_messages(DialogId dialog_id, MessageId from_message_id, int32 offset, int32 limit,
23154                                     int left_tries, bool only_local, Promise<Unit> &&promise) {
23155   load_messages_impl(get_dialog(dialog_id), from_message_id, offset, limit, left_tries, only_local, std::move(promise));
23156 }
23157 
load_messages_impl(const Dialog * d,MessageId from_message_id,int32 offset,int32 limit,int left_tries,bool only_local,Promise<Unit> && promise)23158 void MessagesManager::load_messages_impl(const Dialog *d, MessageId from_message_id, int32 offset, int32 limit,
23159                                          int left_tries, bool only_local, Promise<Unit> &&promise) {
23160   CHECK(d != nullptr);
23161   CHECK(offset <= 0);
23162   CHECK(left_tries > 0);
23163   auto dialog_id = d->dialog_id;
23164   LOG(INFO) << "Load " << (only_local ? "local " : "") << "messages in " << dialog_id << " from " << from_message_id
23165             << " with offset = " << offset << " and limit = " << limit << ". " << left_tries << " tries left";
23166   only_local |= dialog_id.get_type() == DialogType::SecretChat;
23167   if (!only_local && d->have_full_history) {
23168     LOG(INFO) << "Have full history in " << dialog_id << ", so don't need to get chat history from server";
23169     only_local = true;
23170   }
23171   bool from_database = (left_tries > 2 || only_local) && G()->parameters().use_message_db;
23172 
23173   if (from_message_id == MessageId()) {
23174     get_history_from_the_end_impl(d, from_database, only_local, std::move(promise));
23175     return;
23176   }
23177   if ((!d->first_database_message_id.is_valid() || from_message_id <= d->first_database_message_id) &&
23178       !d->have_full_history) {
23179     from_database = false;
23180   }
23181   if (offset >= -1) {
23182     // get history before some server or local message
23183     limit = min(max(limit + offset + 1, MAX_GET_HISTORY / 2), MAX_GET_HISTORY);
23184     offset = -1;
23185   } else {
23186     // get history around some server or local message
23187     int32 messages_to_load = max(MAX_GET_HISTORY, limit);
23188     int32 max_add = max(messages_to_load - limit - 2, 0);
23189     offset -= max_add;
23190     limit = MAX_GET_HISTORY;
23191   }
23192   get_history_impl(d, from_message_id, offset, limit, from_database, only_local, std::move(promise));
23193 }
23194 
get_dialog_scheduled_messages(DialogId dialog_id,bool force,bool ignore_result,Promise<Unit> && promise)23195 vector<MessageId> MessagesManager::get_dialog_scheduled_messages(DialogId dialog_id, bool force, bool ignore_result,
23196                                                                  Promise<Unit> &&promise) {
23197   LOG(INFO) << "Get scheduled messages in " << dialog_id;
23198   if (G()->close_flag()) {
23199     promise.set_error(Global::request_aborted_error());
23200     return {};
23201   }
23202 
23203   Dialog *d = get_dialog_force(dialog_id, "get_dialog_scheduled_messages");
23204   if (d == nullptr) {
23205     promise.set_error(Status::Error(400, "Chat not found"));
23206     return {};
23207   }
23208   if (!have_input_peer(dialog_id, AccessRights::Read)) {
23209     promise.set_error(Status::Error(400, "Can't access the chat"));
23210     return {};
23211   }
23212   if (is_broadcast_channel(dialog_id) &&
23213       !td_->contacts_manager_->get_channel_status(dialog_id.get_channel_id()).can_post_messages()) {
23214     promise.set_error(Status::Error(400, "Not enough rights to get scheduled messages"));
23215     return {};
23216   }
23217 
23218   if (!d->has_loaded_scheduled_messages_from_database) {
23219     load_dialog_scheduled_messages(dialog_id, true, 0, std::move(promise));
23220     return {};
23221   }
23222 
23223   vector<MessageId> message_ids;
23224   find_old_messages(d->scheduled_messages.get(),
23225                     MessageId(ScheduledServerMessageId(), std::numeric_limits<int32>::max(), true), message_ids);
23226   std::reverse(message_ids.begin(), message_ids.end());
23227 
23228   if (G()->parameters().use_message_db) {
23229     bool has_scheduled_database_messages = false;
23230     for (auto &message_id : message_ids) {
23231       CHECK(message_id.is_valid_scheduled());
23232       if (!message_id.is_yet_unsent()) {
23233         has_scheduled_database_messages = true;
23234         break;
23235       }
23236     }
23237     set_dialog_has_scheduled_database_messages(d->dialog_id, has_scheduled_database_messages);
23238   }
23239 
23240   if (d->scheduled_messages_sync_generation != scheduled_messages_sync_generation_) {
23241     vector<uint64> numbers;
23242     for (auto &message_id : message_ids) {
23243       if (!message_id.is_scheduled_server()) {
23244         continue;
23245       }
23246 
23247       numbers.push_back(message_id.get_scheduled_server_message_id().get());
23248       const Message *m = get_message(d, message_id);
23249       CHECK(m != nullptr);
23250       CHECK(m->message_id.get_scheduled_server_message_id() == message_id.get_scheduled_server_message_id());
23251       numbers.push_back(m->edit_date);
23252       numbers.push_back(m->date);
23253     }
23254     auto hash = get_vector_hash(numbers);
23255 
23256     if (!force && (d->has_scheduled_server_messages ||
23257                    (d->scheduled_messages_sync_generation == 0 && !G()->parameters().use_message_db))) {
23258       load_dialog_scheduled_messages(dialog_id, false, hash, std::move(promise));
23259       return {};
23260     }
23261     load_dialog_scheduled_messages(dialog_id, false, hash, Promise<Unit>());
23262   }
23263 
23264   if (!ignore_result) {
23265     d->sent_scheduled_messages = true;
23266   }
23267 
23268   promise.set_value(Unit());
23269   return message_ids;
23270 }
23271 
load_dialog_scheduled_messages(DialogId dialog_id,bool from_database,int64 hash,Promise<Unit> && promise)23272 void MessagesManager::load_dialog_scheduled_messages(DialogId dialog_id, bool from_database, int64 hash,
23273                                                      Promise<Unit> &&promise) {
23274   if (G()->parameters().use_message_db && from_database) {
23275     LOG(INFO) << "Load scheduled messages from database in " << dialog_id;
23276     auto &queries = load_scheduled_messages_from_database_queries_[dialog_id];
23277     queries.push_back(std::move(promise));
23278     if (queries.size() == 1) {
23279       G()->td_db()->get_messages_db_async()->get_scheduled_messages(
23280           dialog_id, 1000,
23281           PromiseCreator::lambda([dialog_id, actor_id = actor_id(this)](vector<MessagesDbDialogMessage> messages) {
23282             send_closure(actor_id, &MessagesManager::on_get_scheduled_messages_from_database, dialog_id,
23283                          std::move(messages));
23284           }));
23285     }
23286   } else {
23287     td_->create_handler<GetAllScheduledMessagesQuery>(std::move(promise))
23288         ->send(dialog_id, hash, scheduled_messages_sync_generation_);
23289   }
23290 }
23291 
on_get_scheduled_messages_from_database(DialogId dialog_id,vector<MessagesDbDialogMessage> && messages)23292 void MessagesManager::on_get_scheduled_messages_from_database(DialogId dialog_id,
23293                                                               vector<MessagesDbDialogMessage> &&messages) {
23294   if (G()->close_flag()) {
23295     auto it = load_scheduled_messages_from_database_queries_.find(dialog_id);
23296     CHECK(it != load_scheduled_messages_from_database_queries_.end());
23297     CHECK(!it->second.empty());
23298     auto promises = std::move(it->second);
23299     load_scheduled_messages_from_database_queries_.erase(it);
23300 
23301     for (auto &promise : promises) {
23302       promise.set_error(Global::request_aborted_error());
23303     }
23304     return;
23305   }
23306   auto d = get_dialog(dialog_id);
23307   CHECK(d != nullptr);
23308   d->has_loaded_scheduled_messages_from_database = true;
23309 
23310   LOG(INFO) << "Receive " << messages.size() << " scheduled messages from database in " << dialog_id;
23311 
23312   Dependencies dependencies;
23313   vector<MessageId> added_message_ids;
23314   for (auto &message_slice : messages) {
23315     auto message = parse_message(dialog_id, message_slice.message_id, message_slice.data, true);
23316     if (message == nullptr) {
23317       continue;
23318     }
23319     message->from_database = true;
23320 
23321     if (get_message(d, message->message_id) != nullptr) {
23322       continue;
23323     }
23324 
23325     bool need_update = false;
23326     Message *m = add_scheduled_message_to_dialog(d, std::move(message), false, &need_update,
23327                                                  "on_get_scheduled_messages_from_database");
23328     if (m != nullptr) {
23329       add_message_dependencies(dependencies, m);
23330       added_message_ids.push_back(m->message_id);
23331     }
23332   }
23333   resolve_dependencies_force(td_, dependencies, "on_get_scheduled_messages_from_database");
23334 
23335   // for (auto message_id : added_message_ids) {
23336   //   send_update_new_message(d, get_message(d, message_id));
23337   // }
23338   send_update_chat_has_scheduled_messages(d, false);
23339 
23340   auto it = load_scheduled_messages_from_database_queries_.find(dialog_id);
23341   CHECK(it != load_scheduled_messages_from_database_queries_.end());
23342   CHECK(!it->second.empty());
23343   auto promises = std::move(it->second);
23344   load_scheduled_messages_from_database_queries_.erase(it);
23345 
23346   for (auto &promise : promises) {
23347     promise.set_value(Unit());
23348   }
23349 }
23350 
get_message_public_forwards(FullMessageId full_message_id,string offset,int32 limit,Promise<td_api::object_ptr<td_api::foundMessages>> && promise)23351 void MessagesManager::get_message_public_forwards(FullMessageId full_message_id, string offset, int32 limit,
23352                                                   Promise<td_api::object_ptr<td_api::foundMessages>> &&promise) {
23353   auto dc_id_promise = PromiseCreator::lambda([actor_id = actor_id(this), full_message_id, offset = std::move(offset),
23354                                                limit, promise = std::move(promise)](Result<DcId> r_dc_id) mutable {
23355     if (r_dc_id.is_error()) {
23356       return promise.set_error(r_dc_id.move_as_error());
23357     }
23358     send_closure(actor_id, &MessagesManager::send_get_message_public_forwards_query, r_dc_id.move_as_ok(),
23359                  full_message_id, std::move(offset), limit, std::move(promise));
23360   });
23361   td_->contacts_manager_->get_channel_statistics_dc_id(full_message_id.get_dialog_id(), false,
23362                                                        std::move(dc_id_promise));
23363 }
23364 
send_get_message_public_forwards_query(DcId dc_id,FullMessageId full_message_id,string offset,int32 limit,Promise<td_api::object_ptr<td_api::foundMessages>> && promise)23365 void MessagesManager::send_get_message_public_forwards_query(
23366     DcId dc_id, FullMessageId full_message_id, string offset, int32 limit,
23367     Promise<td_api::object_ptr<td_api::foundMessages>> &&promise) {
23368   auto dialog_id = full_message_id.get_dialog_id();
23369   Dialog *d = get_dialog_force(dialog_id, "send_get_message_public_forwards_query");
23370   if (d == nullptr) {
23371     return promise.set_error(Status::Error(400, "Chat not found"));
23372   }
23373 
23374   const Message *m = get_message_force(d, full_message_id.get_message_id(), "send_get_message_public_forwards_query");
23375   if (m == nullptr) {
23376     return promise.set_error(Status::Error(400, "Message not found"));
23377   }
23378 
23379   if (m->view_count == 0 || m->forward_info != nullptr || m->had_forward_info || m->message_id.is_scheduled() ||
23380       !m->message_id.is_server()) {
23381     return promise.set_error(Status::Error(400, "Message forwards are inaccessible"));
23382   }
23383 
23384   if (limit <= 0) {
23385     return promise.set_error(Status::Error(400, "Parameter limit must be positive"));
23386   }
23387   if (limit > MAX_SEARCH_MESSAGES) {
23388     limit = MAX_SEARCH_MESSAGES;
23389   }
23390 
23391   int32 offset_date = std::numeric_limits<int32>::max();
23392   DialogId offset_dialog_id;
23393   ServerMessageId offset_message_id;
23394 
23395   if (!offset.empty()) {
23396     auto parts = full_split(offset, ',');
23397     if (parts.size() != 3) {
23398       return promise.set_error(Status::Error(400, "Invalid offset specified"));
23399     }
23400     auto r_offset_date = to_integer_safe<int32>(parts[0]);
23401     auto r_offset_dialog_id = to_integer_safe<int64>(parts[1]);
23402     auto r_offset_message_id = to_integer_safe<int32>(parts[2]);
23403     if (r_offset_date.is_error() || r_offset_dialog_id.is_error() || r_offset_message_id.is_error()) {
23404       return promise.set_error(Status::Error(400, "Invalid offset specified"));
23405     }
23406 
23407     offset_date = r_offset_date.ok();
23408     offset_dialog_id = DialogId(r_offset_dialog_id.ok());
23409     offset_message_id = ServerMessageId(r_offset_message_id.ok());
23410   }
23411 
23412   td_->create_handler<GetMessagePublicForwardsQuery>(std::move(promise))
23413       ->send(dc_id, full_message_id, offset_date, offset_dialog_id, offset_message_id, limit);
23414 }
23415 
get_message_schedule_date(td_api::object_ptr<td_api::MessageSchedulingState> && scheduling_state)23416 Result<int32> MessagesManager::get_message_schedule_date(
23417     td_api::object_ptr<td_api::MessageSchedulingState> &&scheduling_state) {
23418   if (scheduling_state == nullptr) {
23419     return 0;
23420   }
23421 
23422   switch (scheduling_state->get_id()) {
23423     case td_api::messageSchedulingStateSendWhenOnline::ID: {
23424       auto send_date = SCHEDULE_WHEN_ONLINE_DATE;
23425       return send_date;
23426     }
23427     case td_api::messageSchedulingStateSendAtDate::ID: {
23428       auto send_at_date = td_api::move_object_as<td_api::messageSchedulingStateSendAtDate>(scheduling_state);
23429       auto send_date = send_at_date->send_date_;
23430       if (send_date <= 0) {
23431         return Status::Error(400, "Invalid send date specified");
23432       }
23433       if (send_date <= G()->unix_time() + 10) {
23434         return 0;
23435       }
23436       if (send_date - G()->unix_time() > 367 * 86400) {
23437         return Status::Error(400, "Send date is too far in the future");
23438       }
23439       return send_date;
23440     }
23441     default:
23442       UNREACHABLE();
23443       return 0;
23444   }
23445 }
23446 
get_message_sending_state_object(const Message * m) const23447 tl_object_ptr<td_api::MessageSendingState> MessagesManager::get_message_sending_state_object(const Message *m) const {
23448   CHECK(m != nullptr);
23449   if (m->message_id.is_yet_unsent()) {
23450     return td_api::make_object<td_api::messageSendingStatePending>();
23451   }
23452   if (m->is_failed_to_send) {
23453     auto can_retry = can_resend_message(m);
23454     auto need_another_sender =
23455         can_retry && m->send_error_code == 400 && m->send_error_message == CSlice("SEND_AS_PEER_INVALID");
23456     return td_api::make_object<td_api::messageSendingStateFailed>(m->send_error_code, m->send_error_message, can_retry,
23457                                                                   need_another_sender,
23458                                                                   max(m->try_resend_at - Time::now(), 0.0));
23459   }
23460   return nullptr;
23461 }
23462 
get_message_scheduling_state_object(int32 send_date)23463 tl_object_ptr<td_api::MessageSchedulingState> MessagesManager::get_message_scheduling_state_object(int32 send_date) {
23464   if (send_date == SCHEDULE_WHEN_ONLINE_DATE) {
23465     return td_api::make_object<td_api::messageSchedulingStateSendWhenOnline>();
23466   }
23467   return td_api::make_object<td_api::messageSchedulingStateSendAtDate>(send_date);
23468 }
23469 
get_dialog_event_log_message_object(DialogId dialog_id,tl_object_ptr<telegram_api::Message> && message)23470 td_api::object_ptr<td_api::message> MessagesManager::get_dialog_event_log_message_object(
23471     DialogId dialog_id, tl_object_ptr<telegram_api::Message> &&message) {
23472   auto dialog_message = create_message(parse_telegram_api_message(std::move(message), false, "dialog_event_log"),
23473                                        dialog_id.get_type() == DialogType::Channel);
23474   if (dialog_message.second == nullptr || dialog_message.first != dialog_id) {
23475     LOG(ERROR) << "Failed to create event log message in " << dialog_id;
23476     return nullptr;
23477   }
23478   return get_message_object(dialog_id, dialog_message.second.get(), "admin log", true);
23479 }
23480 
get_message_object(FullMessageId full_message_id,const char * source)23481 tl_object_ptr<td_api::message> MessagesManager::get_message_object(FullMessageId full_message_id, const char *source) {
23482   return get_message_object(full_message_id.get_dialog_id(), get_message_force(full_message_id, source), source);
23483 }
23484 
get_message_object(DialogId dialog_id,const Message * m,const char * source,bool for_event_log) const23485 tl_object_ptr<td_api::message> MessagesManager::get_message_object(DialogId dialog_id, const Message *m,
23486                                                                    const char *source, bool for_event_log) const {
23487   if (m == nullptr) {
23488     return nullptr;
23489   }
23490   LOG_CHECK(have_dialog(dialog_id)) << source;
23491 
23492   m->is_update_sent = true;
23493 
23494   auto sending_state = get_message_sending_state_object(m);
23495 
23496   if (for_event_log) {
23497     CHECK(m->message_id.is_server());
23498     CHECK(sending_state == nullptr);
23499   }
23500 
23501   bool can_delete = can_delete_message(dialog_id, m);
23502   bool is_scheduled = m->message_id.is_scheduled();
23503   DialogId my_dialog_id = get_my_dialog_id();
23504   bool can_delete_for_self = false;
23505   bool can_delete_for_all_users = can_delete && can_revoke_message(dialog_id, m);
23506   if (can_delete) {
23507     switch (dialog_id.get_type()) {
23508       case DialogType::User:
23509       case DialogType::Chat:
23510         // TODO allow to delete yet unsent message just for self
23511         can_delete_for_self = !m->message_id.is_yet_unsent() || dialog_id == my_dialog_id;
23512         break;
23513       case DialogType::Channel:
23514       case DialogType::SecretChat:
23515         can_delete_for_self = !can_delete_for_all_users;
23516         break;
23517       case DialogType::None:
23518       default:
23519         UNREACHABLE();
23520     }
23521   }
23522   if (for_event_log) {
23523     can_delete_for_self = false;
23524     can_delete_for_all_users = false;
23525   } else if (is_scheduled) {
23526     can_delete_for_self = (dialog_id == my_dialog_id);
23527     can_delete_for_all_users = !can_delete_for_self;
23528   }
23529 
23530   bool is_outgoing = m->is_outgoing;
23531   if (dialog_id == my_dialog_id) {
23532     // in Saved Messages all non-forwarded messages must be outgoing
23533     // a forwarded message is outgoing, only if it doesn't have from_dialog_id and its sender isn't hidden
23534     // i.e. a message is incoming only if it's a forwarded message with known from_dialog_id or with a hidden sender
23535     auto forward_info = m->forward_info.get();
23536     is_outgoing = is_scheduled || forward_info == nullptr ||
23537                   (!forward_info->from_dialog_id.is_valid() && !is_forward_info_sender_hidden(forward_info));
23538   }
23539 
23540   int32 ttl = m->ttl;
23541   double ttl_expires_in = 0;
23542   if (!for_event_log) {
23543     if (m->ttl_expires_at != 0) {
23544       ttl_expires_in = clamp(m->ttl_expires_at - Time::now(), 1e-3, ttl - 1e-3);
23545     } else {
23546       ttl_expires_in = ttl;
23547     }
23548     if (ttl == 0 && m->ttl_period != 0) {
23549       ttl = m->ttl_period;
23550       ttl_expires_in = clamp(m->date + m->ttl_period - G()->server_time(), 1e-3, ttl - 1e-3);
23551     }
23552   } else {
23553     ttl = 0;
23554   }
23555   auto sender = get_message_sender_object_const(td_, m->sender_user_id, m->sender_dialog_id, source);
23556   auto scheduling_state = is_scheduled ? get_message_scheduling_state_object(m->date) : nullptr;
23557   auto forward_info = get_message_forward_info_object(m->forward_info);
23558   auto interaction_info = get_message_interaction_info_object(dialog_id, m);
23559   auto can_be_saved = can_save_message(dialog_id, m);
23560   auto can_be_edited = for_event_log ? false : can_edit_message(dialog_id, m, false, td_->auth_manager_->is_bot());
23561   auto can_be_forwarded = for_event_log ? false : can_forward_message(dialog_id, m) && can_be_saved;
23562   auto can_get_statistics = for_event_log ? false : can_get_message_statistics(dialog_id, m);
23563   auto can_get_message_thread = for_event_log ? false : get_top_thread_full_message_id(dialog_id, m).is_ok();
23564   auto can_get_viewers = for_event_log ? false : can_get_message_viewers(dialog_id, m).is_ok();
23565   auto can_get_media_timestamp_links = for_event_log ? false : can_get_media_timestamp_link(dialog_id, m).is_ok();
23566   auto via_bot_user_id = td_->contacts_manager_->get_user_id_object(m->via_bot_user_id, "via_bot_user_id");
23567   auto media_album_id = for_event_log ? static_cast<int64>(0) : m->media_album_id;
23568   auto reply_to_message_id = for_event_log ? static_cast<int64>(0) : m->reply_to_message_id.get();
23569   auto reply_in_dialog_id =
23570       reply_to_message_id == 0 ? DialogId() : (m->reply_in_dialog_id.is_valid() ? m->reply_in_dialog_id : dialog_id);
23571   auto top_thread_message_id = for_event_log || is_scheduled ? static_cast<int64>(0) : m->top_thread_message_id.get();
23572   auto contains_unread_mention = for_event_log ? false : m->contains_unread_mention;
23573   auto date = is_scheduled ? 0 : m->date;
23574   auto edit_date = m->hide_edit_date ? 0 : m->edit_date;
23575   auto is_pinned = is_scheduled ? false : m->is_pinned;
23576   auto has_timestamped_media = for_event_log || reply_to_message_id == 0 || m->max_own_media_timestamp >= 0;
23577   auto reply_markup = get_reply_markup_object(m->reply_markup);
23578 
23579   auto live_location_date = m->is_failed_to_send ? 0 : m->date;
23580   auto skip_bot_commands = for_event_log ? true : need_skip_bot_commands(dialog_id, m);
23581   auto max_media_timestamp =
23582       for_event_log ? get_message_own_max_media_timestamp(m) : get_message_max_media_timestamp(m);
23583   auto content = get_message_content_object(m->content.get(), td_, dialog_id, live_location_date, m->is_content_secret,
23584                                             skip_bot_commands, max_media_timestamp);
23585   return make_tl_object<td_api::message>(
23586       m->message_id.get(), std::move(sender), dialog_id.get(), std::move(sending_state), std::move(scheduling_state),
23587       is_outgoing, is_pinned, can_be_edited, can_be_forwarded, can_be_saved, can_delete_for_self,
23588       can_delete_for_all_users, can_get_statistics, can_get_message_thread, can_get_viewers,
23589       can_get_media_timestamp_links, has_timestamped_media, m->is_channel_post, contains_unread_mention, date,
23590       edit_date, std::move(forward_info), std::move(interaction_info), reply_in_dialog_id.get(), reply_to_message_id,
23591       top_thread_message_id, ttl, ttl_expires_in, via_bot_user_id, m->author_signature, media_album_id,
23592       get_restriction_reason_description(m->restriction_reasons), std::move(content), std::move(reply_markup));
23593 }
23594 
get_messages_object(int32 total_count,DialogId dialog_id,const vector<MessageId> & message_ids,bool skip_not_found,const char * source)23595 tl_object_ptr<td_api::messages> MessagesManager::get_messages_object(int32 total_count, DialogId dialog_id,
23596                                                                      const vector<MessageId> &message_ids,
23597                                                                      bool skip_not_found, const char *source) {
23598   Dialog *d = get_dialog(dialog_id);
23599   CHECK(d != nullptr);
23600   auto message_objects = transform(message_ids, [this, dialog_id, d, source](MessageId message_id) {
23601     return get_message_object(dialog_id, get_message_force(d, message_id, source), source);
23602   });
23603   return get_messages_object(total_count, std::move(message_objects), skip_not_found);
23604 }
23605 
get_messages_object(int32 total_count,const vector<FullMessageId> & full_message_ids,bool skip_not_found,const char * source)23606 tl_object_ptr<td_api::messages> MessagesManager::get_messages_object(int32 total_count,
23607                                                                      const vector<FullMessageId> &full_message_ids,
23608                                                                      bool skip_not_found, const char *source) {
23609   auto message_objects = transform(full_message_ids, [this, source](FullMessageId full_message_id) {
23610     return get_message_object(full_message_id, source);
23611   });
23612   return get_messages_object(total_count, std::move(message_objects), skip_not_found);
23613 }
23614 
get_messages_object(int32 total_count,vector<tl_object_ptr<td_api::message>> && messages,bool skip_not_found)23615 tl_object_ptr<td_api::messages> MessagesManager::get_messages_object(int32 total_count,
23616                                                                      vector<tl_object_ptr<td_api::message>> &&messages,
23617                                                                      bool skip_not_found) {
23618   auto message_count = narrow_cast<int32>(messages.size());
23619   if (total_count < message_count) {
23620     if (total_count != -1) {
23621       LOG(ERROR) << "Have wrong total_count = " << total_count << ", while having " << message_count << " messages";
23622     }
23623     total_count = message_count;
23624   }
23625   if (skip_not_found && td::remove(messages, nullptr)) {
23626     total_count -= message_count - static_cast<int32>(messages.size());
23627   }
23628   return td_api::make_object<td_api::messages>(total_count, std::move(messages));
23629 }
23630 
is_anonymous_administrator(DialogId dialog_id,string * author_signature) const23631 bool MessagesManager::is_anonymous_administrator(DialogId dialog_id, string *author_signature) const {
23632   CHECK(dialog_id.is_valid());
23633 
23634   if (is_broadcast_channel(dialog_id)) {
23635     return true;
23636   }
23637 
23638   if (td_->auth_manager_->is_bot()) {
23639     return false;
23640   }
23641 
23642   if (dialog_id.get_type() != DialogType::Channel) {
23643     return false;
23644   }
23645 
23646   auto status = td_->contacts_manager_->get_channel_status(dialog_id.get_channel_id());
23647   if (!status.is_anonymous()) {
23648     return false;
23649   }
23650 
23651   if (author_signature != nullptr) {
23652     *author_signature = status.get_rank();
23653   }
23654   return true;
23655 }
23656 
generate_new_random_id()23657 int64 MessagesManager::generate_new_random_id() {
23658   int64 random_id;
23659   do {
23660     random_id = Random::secure_int64();
23661   } while (random_id == 0 || being_sent_messages_.find(random_id) != being_sent_messages_.end());
23662   return random_id;
23663 }
23664 
create_message_to_send(Dialog * d,MessageId top_thread_message_id,MessageId reply_to_message_id,const MessageSendOptions & options,unique_ptr<MessageContent> && content,bool suppress_reply_info,unique_ptr<MessageForwardInfo> forward_info,bool is_copy,DialogId send_as_dialog_id) const23665 unique_ptr<MessagesManager::Message> MessagesManager::create_message_to_send(
23666     Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id, const MessageSendOptions &options,
23667     unique_ptr<MessageContent> &&content, bool suppress_reply_info, unique_ptr<MessageForwardInfo> forward_info,
23668     bool is_copy, DialogId send_as_dialog_id) const {
23669   CHECK(d != nullptr);
23670   CHECK(!reply_to_message_id.is_scheduled());
23671   CHECK(content != nullptr);
23672 
23673   bool is_scheduled = options.schedule_date != 0;
23674   DialogId dialog_id = d->dialog_id;
23675 
23676   auto dialog_type = dialog_id.get_type();
23677   auto my_id = td_->contacts_manager_->get_my_id();
23678 
23679   auto m = make_unique<Message>();
23680   bool is_channel_post = is_broadcast_channel(dialog_id);
23681   if (is_channel_post) {
23682     // sender of the post can be hidden
23683     if (!is_scheduled && td_->contacts_manager_->get_channel_sign_messages(dialog_id.get_channel_id())) {
23684       m->author_signature = td_->contacts_manager_->get_user_title(my_id);
23685     }
23686     m->sender_dialog_id = dialog_id;
23687   } else {
23688     if (send_as_dialog_id.is_valid()) {
23689       if (send_as_dialog_id.get_type() == DialogType::User) {
23690         m->sender_user_id = send_as_dialog_id.get_user_id();
23691       } else {
23692         m->sender_dialog_id = send_as_dialog_id;
23693       }
23694     } else if (d->default_send_message_as_dialog_id.is_valid()) {
23695       if (d->default_send_message_as_dialog_id.get_type() == DialogType::User) {
23696         m->sender_user_id = my_id;
23697       } else {
23698         m->sender_dialog_id = d->default_send_message_as_dialog_id;
23699       }
23700       m->has_explicit_sender = true;
23701     } else {
23702       if (is_anonymous_administrator(dialog_id, &m->author_signature)) {
23703         m->sender_dialog_id = dialog_id;
23704       } else {
23705         m->sender_user_id = my_id;
23706       }
23707     }
23708   }
23709   m->send_date = G()->unix_time();
23710   m->date = is_scheduled ? options.schedule_date : m->send_date;
23711   m->reply_to_message_id = reply_to_message_id;
23712   if (!is_scheduled) {
23713     m->top_thread_message_id = top_thread_message_id;
23714     if (reply_to_message_id.is_valid()) {
23715       const Message *reply_m = get_message(d, reply_to_message_id);
23716       if (reply_m != nullptr && reply_m->top_thread_message_id.is_valid()) {
23717         m->top_thread_message_id = reply_m->top_thread_message_id;
23718       }
23719     }
23720   }
23721   m->is_channel_post = is_channel_post;
23722   m->is_outgoing = is_scheduled || dialog_id != DialogId(my_id);
23723   m->from_background = options.from_background;
23724   m->view_count = is_channel_post && !is_scheduled ? 1 : 0;
23725   m->forward_count = 0;
23726   if ([&] {
23727         if (suppress_reply_info) {
23728           return false;
23729         }
23730         if (is_scheduled) {
23731           return false;
23732         }
23733         if (dialog_type != DialogType::Channel) {
23734           return false;
23735         }
23736         if (td_->auth_manager_->is_bot()) {
23737           return false;
23738         }
23739         if (is_channel_post) {
23740           return td_->contacts_manager_->get_channel_has_linked_channel(dialog_id.get_channel_id());
23741         }
23742         return !reply_to_message_id.is_valid();
23743       }()) {
23744     m->reply_info.reply_count = 0;
23745     if (is_channel_post) {
23746       auto linked_channel_id = td_->contacts_manager_->get_channel_linked_channel_id(dialog_id.get_channel_id());
23747       if (linked_channel_id.is_valid()) {
23748         m->reply_info.is_comment = true;
23749         m->reply_info.channel_id = linked_channel_id;
23750       }
23751     }
23752   }
23753   m->content = std::move(content);
23754   m->forward_info = std::move(forward_info);
23755   m->is_copy = is_copy || m->forward_info != nullptr;
23756 
23757   if (td_->auth_manager_->is_bot() || options.disable_notification ||
23758       G()->shared_config().get_option_boolean("ignore_default_disable_notification")) {
23759     m->disable_notification = options.disable_notification;
23760   } else {
23761     m->disable_notification = d->notification_settings.silent_send_message;
23762   }
23763 
23764   if (dialog_type == DialogType::SecretChat) {
23765     CHECK(!is_scheduled);
23766     m->ttl = td_->contacts_manager_->get_secret_chat_ttl(dialog_id.get_secret_chat_id());
23767     if (is_service_message_content(m->content->get_type())) {
23768       m->ttl = 0;
23769     }
23770     m->is_content_secret = is_secret_message_content(m->ttl, m->content->get_type());
23771     if (reply_to_message_id.is_valid()) {
23772       // the message was forcely preloaded in get_reply_to_message_id
23773       auto *reply_to_message = get_message(d, reply_to_message_id);
23774       if (reply_to_message != nullptr) {
23775         m->reply_to_random_id = reply_to_message->random_id;
23776       } else {
23777         m->reply_to_message_id = MessageId();
23778       }
23779     }
23780   }
23781   return m;
23782 }
23783 
get_message_to_send(Dialog * d,MessageId top_thread_message_id,MessageId reply_to_message_id,const MessageSendOptions & options,unique_ptr<MessageContent> && content,bool * need_update_dialog_pos,bool suppress_reply_info,unique_ptr<MessageForwardInfo> forward_info,bool is_copy,DialogId send_as_dialog_id)23784 MessagesManager::Message *MessagesManager::get_message_to_send(
23785     Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id, const MessageSendOptions &options,
23786     unique_ptr<MessageContent> &&content, bool *need_update_dialog_pos, bool suppress_reply_info,
23787     unique_ptr<MessageForwardInfo> forward_info, bool is_copy, DialogId send_as_dialog_id) {
23788   d->was_opened = true;
23789 
23790   auto message = create_message_to_send(d, top_thread_message_id, reply_to_message_id, options, std::move(content),
23791                                         suppress_reply_info, std::move(forward_info), is_copy, send_as_dialog_id);
23792 
23793   MessageId message_id = options.schedule_date != 0 ? get_next_yet_unsent_scheduled_message_id(d, options.schedule_date)
23794                                                     : get_next_yet_unsent_message_id(d);
23795   set_message_id(message, message_id);
23796 
23797   message->have_previous = true;
23798   message->have_next = true;
23799 
23800   message->random_id = generate_new_random_id();
23801 
23802   bool need_update = false;
23803   CHECK(have_input_peer(d->dialog_id, AccessRights::Read));
23804   auto result =
23805       add_message_to_dialog(d, std::move(message), true, &need_update, need_update_dialog_pos, "send message");
23806   LOG_CHECK(result != nullptr) << message_id << " " << debug_add_message_to_dialog_fail_reason_;
23807   if (result->message_id.is_scheduled()) {
23808     send_update_chat_has_scheduled_messages(d, false);
23809   }
23810   return result;
23811 }
23812 
begin_send_message(DialogId dialog_id,const Message * m)23813 int64 MessagesManager::begin_send_message(DialogId dialog_id, const Message *m) {
23814   LOG(INFO) << "Begin to send " << FullMessageId(dialog_id, m->message_id) << " with random_id = " << m->random_id;
23815   CHECK(m->random_id != 0 && being_sent_messages_.find(m->random_id) == being_sent_messages_.end());
23816   CHECK(m->message_id.is_yet_unsent());
23817   being_sent_messages_[m->random_id] = FullMessageId(dialog_id, m->message_id);
23818   return m->random_id;
23819 }
23820 
can_send_message(DialogId dialog_id) const23821 Status MessagesManager::can_send_message(DialogId dialog_id) const {
23822   if (!have_input_peer(dialog_id, AccessRights::Write)) {
23823     return Status::Error(400, "Have no write access to the chat");
23824   }
23825 
23826   if (dialog_id.get_type() == DialogType::Channel) {
23827     auto channel_id = dialog_id.get_channel_id();
23828     auto channel_type = td_->contacts_manager_->get_channel_type(channel_id);
23829     auto channel_status = td_->contacts_manager_->get_channel_permissions(channel_id);
23830 
23831     switch (channel_type) {
23832       case ContactsManager::ChannelType::Unknown:
23833       case ContactsManager::ChannelType::Megagroup:
23834         if (!channel_status.can_send_messages()) {
23835           return Status::Error(400, "Have no rights to send a message");
23836         }
23837         break;
23838       case ContactsManager::ChannelType::Broadcast: {
23839         if (!channel_status.can_post_messages()) {
23840           return Status::Error(400, "Need administrator rights in the channel chat");
23841         }
23842         break;
23843       }
23844       default:
23845         UNREACHABLE();
23846     }
23847   }
23848   return Status::OK();
23849 }
23850 
get_persistent_message_id(const Dialog * d,MessageId message_id)23851 MessageId MessagesManager::get_persistent_message_id(const Dialog *d, MessageId message_id) {
23852   if (!message_id.is_valid() && !message_id.is_valid_scheduled()) {
23853     return MessageId();
23854   }
23855   if (message_id.is_yet_unsent()) {
23856     // it is possible that user tries to do something with an already sent message by its temporary id
23857     // we need to use real message in this case and transparently replace message_id
23858     auto it = d->yet_unsent_message_id_to_persistent_message_id.find(message_id);
23859     if (it != d->yet_unsent_message_id_to_persistent_message_id.end()) {
23860       return it->second;
23861     }
23862   }
23863 
23864   return message_id;
23865 }
23866 
get_reply_to_message_id(Dialog * d,MessageId top_thread_message_id,MessageId message_id,bool for_draft)23867 MessageId MessagesManager::get_reply_to_message_id(Dialog *d, MessageId top_thread_message_id, MessageId message_id,
23868                                                    bool for_draft) {
23869   CHECK(d != nullptr);
23870   if (!message_id.is_valid()) {
23871     if (!for_draft && message_id == MessageId() && top_thread_message_id.is_valid() &&
23872         top_thread_message_id.is_server() &&
23873         get_message_force(d, top_thread_message_id, "get_reply_to_message_id 1") != nullptr) {
23874       return top_thread_message_id;
23875     }
23876     return MessageId();
23877   }
23878   message_id = get_persistent_message_id(d, message_id);
23879   const Message *m = get_message_force(d, message_id, "get_reply_to_message_id 2");
23880   if (m == nullptr || m->message_id.is_yet_unsent() ||
23881       (m->message_id.is_local() && d->dialog_id.get_type() != DialogType::SecretChat)) {
23882     if (message_id.is_server() && d->dialog_id.get_type() != DialogType::SecretChat &&
23883         message_id > d->last_new_message_id && message_id <= d->max_notification_message_id) {
23884       // allow to reply yet unreceived server message
23885       return message_id;
23886     }
23887     if (!for_draft && top_thread_message_id.is_valid() && top_thread_message_id.is_server() &&
23888         get_message_force(d, top_thread_message_id, "get_reply_to_message_id 3") != nullptr) {
23889       return top_thread_message_id;
23890     }
23891 
23892     // TODO local replies to local messages can be allowed
23893     // TODO replies to yet unsent messages can be allowed with special handling of them on application restart
23894     return MessageId();
23895   }
23896   return m->message_id;
23897 }
23898 
fix_server_reply_to_message_id(DialogId dialog_id,MessageId message_id,DialogId reply_in_dialog_id,MessageId & reply_to_message_id)23899 void MessagesManager::fix_server_reply_to_message_id(DialogId dialog_id, MessageId message_id,
23900                                                      DialogId reply_in_dialog_id, MessageId &reply_to_message_id) {
23901   CHECK(!reply_to_message_id.is_scheduled());
23902   if (!reply_to_message_id.is_valid()) {
23903     if (reply_to_message_id != MessageId()) {
23904       LOG(ERROR) << "Receive reply to " << reply_to_message_id << " for " << message_id << " in " << dialog_id;
23905       reply_to_message_id = MessageId();
23906     }
23907     return;
23908   }
23909 
23910   if (!message_id.is_scheduled() && !reply_in_dialog_id.is_valid() && reply_to_message_id >= message_id) {
23911     if (!can_overflow_message_id(dialog_id)) {
23912       LOG(ERROR) << "Receive reply to wrong " << reply_to_message_id << " in " << message_id << " in " << dialog_id;
23913     }
23914     reply_to_message_id = MessageId();
23915   }
23916 }
23917 
get_message_file_ids(const Message * m) const23918 vector<FileId> MessagesManager::get_message_file_ids(const Message *m) const {
23919   CHECK(m != nullptr);
23920   return get_message_content_file_ids(m->content.get(), td_);
23921 }
23922 
cancel_upload_message_content_files(const MessageContent * content)23923 void MessagesManager::cancel_upload_message_content_files(const MessageContent *content) {
23924   auto file_id = get_message_content_upload_file_id(content);
23925   // always cancel file upload, it should be a no-op in the worst case
23926   if (being_uploaded_files_.erase(file_id) || file_id.is_valid()) {
23927     cancel_upload_file(file_id);
23928   }
23929   file_id = get_message_content_thumbnail_file_id(content, td_);
23930   if (being_uploaded_thumbnails_.erase(file_id) || file_id.is_valid()) {
23931     cancel_upload_file(file_id);
23932   }
23933 }
23934 
cancel_upload_file(FileId file_id)23935 void MessagesManager::cancel_upload_file(FileId file_id) {
23936   // send the request later so they doesn't interfere with other actions
23937   // for example merge, supposed to happen soon, can auto-cancel the upload
23938   LOG(INFO) << "Cancel upload of file " << file_id;
23939   send_closure_later(G()->file_manager(), &FileManager::cancel_upload, file_id);
23940 }
23941 
cancel_send_message_query(DialogId dialog_id,Message * m)23942 void MessagesManager::cancel_send_message_query(DialogId dialog_id, Message *m) {
23943   CHECK(m != nullptr);
23944   CHECK(m->content != nullptr);
23945   CHECK(m->message_id.is_valid() || m->message_id.is_valid_scheduled());
23946   CHECK(m->message_id.is_yet_unsent());
23947   LOG(INFO) << "Cancel send message query for " << m->message_id;
23948 
23949   cancel_upload_message_content_files(m->content.get());
23950 
23951   CHECK(m->edited_content == nullptr);
23952 
23953   if (!m->send_query_ref.empty()) {
23954     LOG(INFO) << "Cancel send query for " << m->message_id;
23955     cancel_query(m->send_query_ref);
23956     m->send_query_ref = NetQueryRef();
23957   }
23958 
23959   if (m->send_message_log_event_id != 0) {
23960     LOG(INFO) << "Delete send message log event for " << m->message_id;
23961     binlog_erase(G()->td_db()->get_binlog(), m->send_message_log_event_id);
23962     m->send_message_log_event_id = 0;
23963   }
23964 
23965   if (m->reply_to_message_id.is_valid() && !m->reply_to_message_id.is_yet_unsent()) {
23966     auto it = replied_by_yet_unsent_messages_.find({dialog_id, m->reply_to_message_id});
23967     CHECK(it != replied_by_yet_unsent_messages_.end());
23968     it->second--;
23969     CHECK(it->second >= 0);
23970     if (it->second == 0) {
23971       replied_by_yet_unsent_messages_.erase(it);
23972     }
23973   }
23974 
23975   if (m->media_album_id != 0) {
23976     send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id, dialog_id,
23977                        m->message_id, Status::OK());
23978   }
23979 
23980   if (!m->message_id.is_scheduled() && G()->parameters().use_file_db &&
23981       !m->is_copy) {  // ResourceManager::Mode::Baseline
23982     auto queue_id = get_sequence_dispatcher_id(dialog_id, m->content->get_type());
23983     if (queue_id & 1) {
23984       auto queue_it = yet_unsent_media_queues_.find(queue_id);
23985       if (queue_it != yet_unsent_media_queues_.end()) {
23986         auto &queue = queue_it->second;
23987         LOG(INFO) << "Delete " << m->message_id << " from queue " << queue_id;
23988         if (queue.erase(m->message_id) != 0) {
23989           if (queue.empty()) {
23990             yet_unsent_media_queues_.erase(queue_it);
23991           } else {
23992             // send later, because do_delete_all_dialog_messages can be called right now
23993             send_closure_later(actor_id(this), &MessagesManager::on_yet_unsent_media_queue_updated, dialog_id);
23994           }
23995         }
23996       }
23997     }
23998   }
23999 }
24000 
cancel_send_deleted_message(DialogId dialog_id,Message * m,bool is_permanently_deleted)24001 void MessagesManager::cancel_send_deleted_message(DialogId dialog_id, Message *m, bool is_permanently_deleted) {
24002   CHECK(m != nullptr);
24003   if (m->message_id.is_yet_unsent()) {
24004     cancel_send_message_query(dialog_id, m);
24005   } else if (is_permanently_deleted || !m->message_id.is_scheduled()) {
24006     cancel_edit_message_media(dialog_id, m, "Message was deleted");
24007   }
24008 }
24009 
is_message_auto_read(DialogId dialog_id,bool is_outgoing) const24010 bool MessagesManager::is_message_auto_read(DialogId dialog_id, bool is_outgoing) const {
24011   switch (dialog_id.get_type()) {
24012     case DialogType::User: {
24013       auto user_id = dialog_id.get_user_id();
24014       if (user_id == td_->contacts_manager_->get_my_id()) {
24015         return true;
24016       }
24017       if (is_outgoing && td_->contacts_manager_->is_user_bot(user_id) &&
24018           !td_->contacts_manager_->is_user_support(user_id)) {
24019         return true;
24020       }
24021       return false;
24022     }
24023     case DialogType::Chat:
24024       // TODO auto_read message content and messages sent to group with bots only
24025       return false;
24026     case DialogType::Channel:
24027       return is_outgoing && is_broadcast_channel(dialog_id);
24028     case DialogType::SecretChat:
24029       return false;
24030     case DialogType::None:
24031       return false;
24032     default:
24033       UNREACHABLE();
24034       return false;
24035   }
24036 }
24037 
add_message_dependencies(Dependencies & dependencies,const Message * m)24038 void MessagesManager::add_message_dependencies(Dependencies &dependencies, const Message *m) {
24039   dependencies.user_ids.insert(m->sender_user_id);
24040   add_dialog_and_dependencies(dependencies, m->sender_dialog_id);
24041   add_dialog_and_dependencies(dependencies, m->reply_in_dialog_id);
24042   add_dialog_and_dependencies(dependencies, m->real_forward_from_dialog_id);
24043   dependencies.user_ids.insert(m->via_bot_user_id);
24044   if (m->forward_info != nullptr) {
24045     dependencies.user_ids.insert(m->forward_info->sender_user_id);
24046     add_dialog_and_dependencies(dependencies, m->forward_info->sender_dialog_id);
24047     add_dialog_and_dependencies(dependencies, m->forward_info->from_dialog_id);
24048   }
24049   for (auto recent_replier_dialog_id : m->reply_info.recent_replier_dialog_ids) {
24050     add_message_sender_dependencies(dependencies, recent_replier_dialog_id);
24051   }
24052   add_message_content_dependencies(dependencies, m->content.get());
24053   add_reply_markup_dependencies(dependencies, m->reply_markup.get());
24054 }
24055 
get_dialog_send_message_as_dialog_ids(DialogId dialog_id,Promise<td_api::object_ptr<td_api::messageSenders>> && promise,bool is_recursive)24056 void MessagesManager::get_dialog_send_message_as_dialog_ids(
24057     DialogId dialog_id, Promise<td_api::object_ptr<td_api::messageSenders>> &&promise, bool is_recursive) {
24058   TRY_STATUS_PROMISE(promise, G()->close_status());
24059 
24060   const Dialog *d = get_dialog_force(dialog_id, "get_group_call_join_as");
24061   if (d == nullptr) {
24062     return promise.set_error(Status::Error(400, "Chat not found"));
24063   }
24064   if (!have_input_peer(dialog_id, AccessRights::Read)) {
24065     return promise.set_error(Status::Error(400, "Can't access chat"));
24066   }
24067   if (!d->default_send_message_as_dialog_id.is_valid()) {
24068     return promise.set_value(td_api::make_object<td_api::messageSenders>());
24069   }
24070   CHECK(dialog_id.get_type() == DialogType::Channel);
24071 
24072   if (created_public_broadcasts_inited_) {
24073     auto senders = td_api::make_object<td_api::messageSenders>();
24074     if (!created_public_broadcasts_.empty()) {
24075       auto add_sender = [&senders, td = td_](DialogId dialog_id) {
24076         senders->total_count_++;
24077         senders->senders_.push_back(get_message_sender_object_const(td, dialog_id, "add_sender"));
24078       };
24079       if (is_anonymous_administrator(dialog_id, nullptr)) {
24080         add_sender(dialog_id);
24081       } else {
24082         add_sender(get_my_dialog_id());
24083       }
24084       for (auto channel_id : created_public_broadcasts_) {
24085         add_sender(DialogId(channel_id));
24086       }
24087     }
24088     return promise.set_value(std::move(senders));
24089   }
24090 
24091   CHECK(!is_recursive);
24092   auto new_promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, promise = std::move(promise)](
24093                                                 Result<td_api::object_ptr<td_api::chats>> &&result) mutable {
24094     if (result.is_error()) {
24095       promise.set_error(result.move_as_error());
24096     } else {
24097       send_closure_later(actor_id, &MessagesManager::get_dialog_send_message_as_dialog_ids, dialog_id,
24098                          std::move(promise), true);
24099     }
24100   });
24101   td_->contacts_manager_->get_created_public_dialogs(PublicDialogType::HasUsername, std::move(new_promise), true);
24102 }
24103 
set_dialog_default_send_message_as_dialog_id(DialogId dialog_id,DialogId message_sender_dialog_id,Promise<Unit> && promise)24104 void MessagesManager::set_dialog_default_send_message_as_dialog_id(DialogId dialog_id,
24105                                                                    DialogId message_sender_dialog_id,
24106                                                                    Promise<Unit> &&promise) {
24107   Dialog *d = get_dialog_force(dialog_id, "set_dialog_default_send_message_as_dialog_id");
24108   if (d == nullptr) {
24109     return promise.set_error(Status::Error(400, "Chat not found"));
24110   }
24111   if (!d->default_send_message_as_dialog_id.is_valid()) {
24112     return promise.set_error(Status::Error(400, "Can't change message sender in the chat"));
24113   }
24114   // checked in on_update_dialog_default_send_message_as_dialog_id
24115   CHECK(dialog_id.get_type() == DialogType::Channel && !is_broadcast_channel(dialog_id));
24116   if (!have_input_peer(dialog_id, AccessRights::Read)) {
24117     return promise.set_error(Status::Error(400, "Can't access the chat"));
24118   }
24119 
24120   bool is_anonymous = is_anonymous_administrator(dialog_id, nullptr);
24121   switch (message_sender_dialog_id.get_type()) {
24122     case DialogType::User:
24123       if (message_sender_dialog_id != DialogId(td_->contacts_manager_->get_my_id())) {
24124         return promise.set_error(Status::Error(400, "Can't send messages as another user"));
24125       }
24126       if (is_anonymous) {
24127         return promise.set_error(Status::Error(400, "Can't send messages as self"));
24128       }
24129       break;
24130     case DialogType::Chat:
24131     case DialogType::Channel:
24132     case DialogType::SecretChat:
24133       if (is_anonymous && dialog_id == message_sender_dialog_id) {
24134         break;
24135       }
24136       if (!is_broadcast_channel(message_sender_dialog_id) ||
24137           td_->contacts_manager_->get_channel_username(dialog_id.get_channel_id()).empty()) {
24138         return promise.set_error(Status::Error(400, "Message sender chat must be a public channel"));
24139       }
24140       break;
24141     default:
24142       UNREACHABLE();
24143       return promise.set_error(Status::Error(400, "Invalid default participant identifier specified"));
24144   }
24145   if (!have_input_peer(message_sender_dialog_id, AccessRights::Read)) {
24146     return promise.set_error(Status::Error(400, "Can't access specified default message sender chat"));
24147   }
24148 
24149   {
24150     auto it = set_typing_query_.find(dialog_id);
24151     if (it != set_typing_query_.end()) {
24152       if (!it->second.empty()) {
24153         cancel_query(it->second);
24154       }
24155       set_typing_query_.erase(it);
24156     }
24157   }
24158 
24159   // TODO save order with all types of messages
24160   send_closure(td_->create_net_actor<SaveDefaultSendAsActor>(std::move(promise)), &SaveDefaultSendAsActor::send,
24161                dialog_id, message_sender_dialog_id, get_sequence_dispatcher_id(dialog_id, MessageContentType::Text));
24162 
24163   on_update_dialog_default_send_message_as_dialog_id(dialog_id, message_sender_dialog_id, true);
24164 }
24165 
24166 class MessagesManager::SendMessageLogEvent {
24167  public:
24168   DialogId dialog_id;
24169   const Message *m_in;
24170   unique_ptr<Message> m_out;
24171 
SendMessageLogEvent()24172   SendMessageLogEvent() : dialog_id(), m_in(nullptr) {
24173   }
24174 
SendMessageLogEvent(DialogId dialog_id,const Message * m)24175   SendMessageLogEvent(DialogId dialog_id, const Message *m) : dialog_id(dialog_id), m_in(m) {
24176   }
24177 
24178   template <class StorerT>
store(StorerT & storer) const24179   void store(StorerT &storer) const {
24180     td::store(dialog_id, storer);
24181     td::store(*m_in, storer);
24182   }
24183 
24184   template <class ParserT>
parse(ParserT & parser)24185   void parse(ParserT &parser) {
24186     td::parse(dialog_id, parser);
24187     td::parse(m_out, parser);
24188   }
24189 };
24190 
send_message(DialogId dialog_id,MessageId top_thread_message_id,MessageId reply_to_message_id,tl_object_ptr<td_api::messageSendOptions> && options,tl_object_ptr<td_api::ReplyMarkup> && reply_markup,tl_object_ptr<td_api::InputMessageContent> && input_message_content)24191 Result<td_api::object_ptr<td_api::message>> MessagesManager::send_message(
24192     DialogId dialog_id, MessageId top_thread_message_id, MessageId reply_to_message_id,
24193     tl_object_ptr<td_api::messageSendOptions> &&options, tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
24194     tl_object_ptr<td_api::InputMessageContent> &&input_message_content) {
24195   if (input_message_content == nullptr) {
24196     return Status::Error(400, "Can't send message without content");
24197   }
24198 
24199   Dialog *d = get_dialog_force(dialog_id, "send_message");
24200   if (d == nullptr) {
24201     return Status::Error(400, "Chat not found");
24202   }
24203 
24204   LOG(INFO) << "Begin to send message to " << dialog_id << " in reply to " << reply_to_message_id;
24205 
24206   reply_to_message_id = get_reply_to_message_id(d, top_thread_message_id, reply_to_message_id, false);
24207 
24208   if (input_message_content->get_id() == td_api::inputMessageForwarded::ID) {
24209     auto input_message = td_api::move_object_as<td_api::inputMessageForwarded>(input_message_content);
24210     TRY_RESULT(copy_options, process_message_copy_options(dialog_id, std::move(input_message->copy_options_)));
24211     copy_options.top_thread_message_id = top_thread_message_id;
24212     copy_options.reply_to_message_id = reply_to_message_id;
24213     TRY_RESULT_ASSIGN(copy_options.reply_markup, get_dialog_reply_markup(dialog_id, std::move(reply_markup)));
24214     return forward_message(dialog_id, DialogId(input_message->from_chat_id_), MessageId(input_message->message_id_),
24215                            std::move(options), input_message->in_game_share_, std::move(copy_options));
24216   }
24217 
24218   TRY_STATUS(can_send_message(dialog_id));
24219   TRY_RESULT(message_reply_markup, get_dialog_reply_markup(dialog_id, std::move(reply_markup)));
24220   TRY_RESULT(message_content, process_input_message_content(dialog_id, std::move(input_message_content)));
24221   TRY_RESULT(message_send_options, process_message_send_options(dialog_id, std::move(options)));
24222   TRY_STATUS(can_use_message_send_options(message_send_options, message_content));
24223   TRY_STATUS(can_use_top_thread_message_id(d, top_thread_message_id, reply_to_message_id));
24224 
24225   // there must be no errors after get_message_to_send call
24226 
24227   bool need_update_dialog_pos = false;
24228   Message *m = get_message_to_send(d, top_thread_message_id, reply_to_message_id, message_send_options,
24229                                    dup_message_content(td_, dialog_id, message_content.content.get(),
24230                                                        MessageContentDupType::Send, MessageCopyOptions()),
24231                                    &need_update_dialog_pos, false, nullptr, message_content.via_bot_user_id.is_valid());
24232   m->reply_markup = std::move(message_reply_markup);
24233   m->via_bot_user_id = message_content.via_bot_user_id;
24234   m->disable_web_page_preview = message_content.disable_web_page_preview;
24235   m->clear_draft = message_content.clear_draft;
24236   if (message_content.ttl > 0) {
24237     m->ttl = message_content.ttl;
24238     m->is_content_secret = is_secret_message_content(m->ttl, m->content->get_type());
24239   }
24240   m->send_emoji = std::move(message_content.emoji);
24241 
24242   if (message_content.clear_draft) {
24243     if (top_thread_message_id.is_valid()) {
24244       set_dialog_draft_message(dialog_id, top_thread_message_id, nullptr).ignore();
24245     } else {
24246       update_dialog_draft_message(d, nullptr, false, !need_update_dialog_pos);
24247     }
24248   }
24249 
24250   save_send_message_log_event(dialog_id, m);
24251   do_send_message(dialog_id, m);
24252 
24253   send_update_new_message(d, m);
24254   if (need_update_dialog_pos) {
24255     send_update_chat_last_message(d, "send_message");
24256   }
24257 
24258   return get_message_object(dialog_id, m, "send_message");
24259 }
24260 
process_input_message_content(DialogId dialog_id,tl_object_ptr<td_api::InputMessageContent> && input_message_content)24261 Result<InputMessageContent> MessagesManager::process_input_message_content(
24262     DialogId dialog_id, tl_object_ptr<td_api::InputMessageContent> &&input_message_content) {
24263   if (input_message_content == nullptr) {
24264     return Status::Error(400, "Can't send message without content");
24265   }
24266 
24267   if (input_message_content->get_id() == td_api::inputMessageForwarded::ID) {
24268     // for sendMessageAlbum/editMessageMedia/addLocalMessage
24269     auto input_message = td_api::move_object_as<td_api::inputMessageForwarded>(input_message_content);
24270     TRY_RESULT(copy_options, process_message_copy_options(dialog_id, std::move(input_message->copy_options_)));
24271     if (!copy_options.send_copy) {
24272       return Status::Error(400, "Can't use forwarded message");
24273     }
24274 
24275     DialogId from_dialog_id(input_message->from_chat_id_);
24276     Dialog *from_dialog = get_dialog_force(from_dialog_id, "send_message copy");
24277     if (from_dialog == nullptr) {
24278       return Status::Error(400, "Chat to copy message from not found");
24279     }
24280     if (!have_input_peer(from_dialog_id, AccessRights::Read)) {
24281       return Status::Error(400, "Can't access the chat to copy message from");
24282     }
24283     if (from_dialog_id.get_type() == DialogType::SecretChat) {
24284       return Status::Error(400, "Can't copy message from secret chats");
24285     }
24286     MessageId message_id = get_persistent_message_id(from_dialog, MessageId(input_message->message_id_));
24287 
24288     const Message *copied_message = get_message_force(from_dialog, message_id, "process_input_message_content");
24289     if (copied_message == nullptr) {
24290       return Status::Error(400, "Can't find message to copy");
24291     }
24292     if (!can_forward_message(from_dialog_id, copied_message)) {
24293       return Status::Error(400, "Can't copy message");
24294     }
24295     if (!can_save_message(from_dialog_id, copied_message) && !td_->auth_manager_->is_bot()) {
24296       return Status::Error(400, "Message copying is restricted");
24297     }
24298 
24299     unique_ptr<MessageContent> content = dup_message_content(td_, dialog_id, copied_message->content.get(),
24300                                                              MessageContentDupType::Copy, std::move(copy_options));
24301     if (content == nullptr) {
24302       return Status::Error(400, "Can't copy message content");
24303     }
24304 
24305     return InputMessageContent(std::move(content), get_message_disable_web_page_preview(copied_message), false, 0,
24306                                UserId(), copied_message->send_emoji);
24307   }
24308 
24309   TRY_RESULT(content, get_input_message_content(dialog_id, std::move(input_message_content), td_));
24310 
24311   if (content.ttl < 0 || content.ttl > MAX_PRIVATE_MESSAGE_TTL) {
24312     return Status::Error(400, "Invalid message content TTL specified");
24313   }
24314   if (content.ttl > 0 && dialog_id.get_type() != DialogType::User) {
24315     return Status::Error(400, "Message content TTL can be specified only in private chats");
24316   }
24317 
24318   if (dialog_id != DialogId()) {
24319     TRY_STATUS(can_send_message_content(dialog_id, content.content.get(), false, td_));
24320   }
24321 
24322   return std::move(content);
24323 }
24324 
process_message_copy_options(DialogId dialog_id,tl_object_ptr<td_api::messageCopyOptions> && options) const24325 Result<MessageCopyOptions> MessagesManager::process_message_copy_options(
24326     DialogId dialog_id, tl_object_ptr<td_api::messageCopyOptions> &&options) const {
24327   if (options == nullptr || !options->send_copy_) {
24328     return MessageCopyOptions();
24329   }
24330   MessageCopyOptions result;
24331   result.send_copy = true;
24332   result.replace_caption = options->replace_caption_;
24333   if (result.replace_caption) {
24334     TRY_RESULT_ASSIGN(result.new_caption,
24335                       process_input_caption(td_->contacts_manager_.get(), dialog_id, std::move(options->new_caption_),
24336                                             td_->auth_manager_->is_bot()));
24337   }
24338   return std::move(result);
24339 }
24340 
process_message_send_options(DialogId dialog_id,tl_object_ptr<td_api::messageSendOptions> && options) const24341 Result<MessagesManager::MessageSendOptions> MessagesManager::process_message_send_options(
24342     DialogId dialog_id, tl_object_ptr<td_api::messageSendOptions> &&options) const {
24343   MessageSendOptions result;
24344   if (options != nullptr) {
24345     result.disable_notification = options->disable_notification_;
24346     result.from_background = options->from_background_;
24347     TRY_RESULT_ASSIGN(result.schedule_date, get_message_schedule_date(std::move(options->scheduling_state_)));
24348   }
24349 
24350   auto dialog_type = dialog_id.get_type();
24351   if (result.schedule_date != 0) {
24352     if (dialog_type == DialogType::SecretChat) {
24353       return Status::Error(400, "Can't schedule messages in secret chats");
24354     }
24355     if (td_->auth_manager_->is_bot()) {
24356       return Status::Error(400, "Bots can't send scheduled messages");
24357     }
24358   }
24359   if (result.schedule_date == SCHEDULE_WHEN_ONLINE_DATE) {
24360     if (dialog_type != DialogType::User) {
24361       return Status::Error(400, "Messages can be scheduled till online only in private chats");
24362     }
24363     if (dialog_id == get_my_dialog_id()) {
24364       return Status::Error(400, "Can't scheduled till online messages in chat with self");
24365     }
24366   }
24367 
24368   return result;
24369 }
24370 
can_use_message_send_options(const MessageSendOptions & options,const unique_ptr<MessageContent> & content,int32 ttl)24371 Status MessagesManager::can_use_message_send_options(const MessageSendOptions &options,
24372                                                      const unique_ptr<MessageContent> &content, int32 ttl) {
24373   if (options.schedule_date != 0) {
24374     if (ttl > 0) {
24375       return Status::Error(400, "Can't send scheduled self-destructing messages");
24376     }
24377     if (content->get_type() == MessageContentType::LiveLocation) {
24378       return Status::Error(400, "Can't send scheduled live location messages");
24379     }
24380   }
24381 
24382   return Status::OK();
24383 }
24384 
can_use_message_send_options(const MessageSendOptions & options,const InputMessageContent & content)24385 Status MessagesManager::can_use_message_send_options(const MessageSendOptions &options,
24386                                                      const InputMessageContent &content) {
24387   return can_use_message_send_options(options, content.content, content.ttl);
24388 }
24389 
can_use_top_thread_message_id(Dialog * d,MessageId top_thread_message_id,MessageId reply_to_message_id)24390 Status MessagesManager::can_use_top_thread_message_id(Dialog *d, MessageId top_thread_message_id,
24391                                                       MessageId reply_to_message_id) {
24392   if (top_thread_message_id == MessageId()) {
24393     return Status::OK();
24394   }
24395 
24396   if (!top_thread_message_id.is_valid() || !top_thread_message_id.is_server()) {
24397     return Status::Error(400, "Invalid message thread ID specified");
24398   }
24399   if (d->dialog_id.get_type() != DialogType::Channel || is_broadcast_channel(d->dialog_id)) {
24400     return Status::Error(400, "Chat doesn't have threads");
24401   }
24402   if (reply_to_message_id.is_valid()) {
24403     const Message *reply_m = get_message_force(d, reply_to_message_id, "can_use_top_thread_message_id 1");
24404     if (reply_m != nullptr && top_thread_message_id != reply_m->top_thread_message_id) {
24405       if (reply_m->top_thread_message_id.is_valid() || reply_m->media_album_id == 0) {
24406         return Status::Error(400, "The message to reply is not in the specified message thread");
24407       }
24408 
24409       // if the message is in an album and not in the thread, it can be in the album of top_thread_message_id
24410       const Message *top_m = get_message_force(d, top_thread_message_id, "can_use_top_thread_message_id 2");
24411       if (top_m != nullptr &&
24412           (top_m->media_album_id != reply_m->media_album_id || top_m->top_thread_message_id != top_m->message_id)) {
24413         return Status::Error(400, "The message to reply is not in the specified message thread root album");
24414       }
24415     }
24416   }
24417 
24418   return Status::OK();
24419 }
24420 
generate_new_media_album_id()24421 int64 MessagesManager::generate_new_media_album_id() {
24422   int64 media_album_id = 0;
24423   do {
24424     media_album_id = Random::secure_int64();
24425   } while (media_album_id >= 0 || pending_message_group_sends_.count(media_album_id) != 0);
24426   return media_album_id;
24427 }
24428 
send_message_group(DialogId dialog_id,MessageId top_thread_message_id,MessageId reply_to_message_id,tl_object_ptr<td_api::messageSendOptions> && options,vector<tl_object_ptr<td_api::InputMessageContent>> && input_message_contents)24429 Result<vector<MessageId>> MessagesManager::send_message_group(
24430     DialogId dialog_id, MessageId top_thread_message_id, MessageId reply_to_message_id,
24431     tl_object_ptr<td_api::messageSendOptions> &&options,
24432     vector<tl_object_ptr<td_api::InputMessageContent>> &&input_message_contents) {
24433   if (input_message_contents.size() > MAX_GROUPED_MESSAGES) {
24434     return Status::Error(400, "Too much messages to send as an album");
24435   }
24436   if (input_message_contents.empty()) {
24437     return Status::Error(400, "There are no messages to send");
24438   }
24439 
24440   Dialog *d = get_dialog_force(dialog_id, "send_message_group");
24441   if (d == nullptr) {
24442     return Status::Error(400, "Chat not found");
24443   }
24444 
24445   TRY_STATUS(can_send_message(dialog_id));
24446   TRY_RESULT(message_send_options, process_message_send_options(dialog_id, std::move(options)));
24447 
24448   vector<std::pair<unique_ptr<MessageContent>, int32>> message_contents;
24449   std::unordered_set<MessageContentType, MessageContentTypeHash> message_content_types;
24450   for (auto &input_message_content : input_message_contents) {
24451     TRY_RESULT(message_content, process_input_message_content(dialog_id, std::move(input_message_content)));
24452     TRY_STATUS(can_use_message_send_options(message_send_options, message_content));
24453     auto message_content_type = message_content.content->get_type();
24454     if (!is_allowed_media_group_content(message_content_type)) {
24455       return Status::Error(400, "Invalid message content type");
24456     }
24457     message_content_types.insert(message_content_type);
24458 
24459     message_contents.emplace_back(std::move(message_content.content), message_content.ttl);
24460   }
24461   if (message_content_types.size() > 1) {
24462     for (auto message_content_type : message_content_types) {
24463       if (is_homogenous_media_group_content(message_content_type)) {
24464         return Status::Error(400, PSLICE() << message_content_type << " can't be mixed with other media types");
24465       }
24466     }
24467   }
24468 
24469   reply_to_message_id = get_reply_to_message_id(d, top_thread_message_id, reply_to_message_id, false);
24470   TRY_STATUS(can_use_top_thread_message_id(d, top_thread_message_id, reply_to_message_id));
24471 
24472   int64 media_album_id = 0;
24473   if (message_contents.size() > 1) {
24474     media_album_id = generate_new_media_album_id();
24475   }
24476 
24477   // there must be no errors after get_message_to_send calls
24478 
24479   vector<MessageId> result;
24480   bool need_update_dialog_pos = false;
24481   for (size_t i = 0; i < message_contents.size(); i++) {
24482     auto &message_content = message_contents[i];
24483     Message *m = get_message_to_send(d, top_thread_message_id, reply_to_message_id, message_send_options,
24484                                      dup_message_content(td_, dialog_id, message_content.first.get(),
24485                                                          MessageContentDupType::Send, MessageCopyOptions()),
24486                                      &need_update_dialog_pos, i != 0);
24487     result.push_back(m->message_id);
24488     auto ttl = message_content.second;
24489     if (ttl > 0) {
24490       m->ttl = ttl;
24491       m->is_content_secret = is_secret_message_content(m->ttl, m->content->get_type());
24492     }
24493     m->media_album_id = media_album_id;
24494 
24495     save_send_message_log_event(dialog_id, m);
24496     do_send_message(dialog_id, m);
24497 
24498     send_update_new_message(d, m);
24499   }
24500 
24501   if (need_update_dialog_pos) {
24502     send_update_chat_last_message(d, "send_message_group");
24503   }
24504 
24505   return result;
24506 }
24507 
save_send_message_log_event(DialogId dialog_id,const Message * m)24508 void MessagesManager::save_send_message_log_event(DialogId dialog_id, const Message *m) {
24509   if (!G()->parameters().use_message_db) {
24510     return;
24511   }
24512 
24513   CHECK(m != nullptr);
24514   LOG(INFO) << "Save " << FullMessageId(dialog_id, m->message_id) << " to binlog";
24515   auto log_event = SendMessageLogEvent(dialog_id, m);
24516   CHECK(m->send_message_log_event_id == 0);
24517   m->send_message_log_event_id =
24518       binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::SendMessage, get_log_event_storer(log_event));
24519 }
24520 
do_send_message(DialogId dialog_id,const Message * m,vector<int> bad_parts)24521 void MessagesManager::do_send_message(DialogId dialog_id, const Message *m, vector<int> bad_parts) {
24522   bool is_edit = m->message_id.is_any_server();
24523   LOG(INFO) << "Do " << (is_edit ? "edit" : "send") << ' ' << FullMessageId(dialog_id, m->message_id);
24524   bool is_secret = dialog_id.get_type() == DialogType::SecretChat;
24525 
24526   if (m->media_album_id != 0 && bad_parts.empty() && !is_secret && !is_edit) {
24527     auto &request = pending_message_group_sends_[m->media_album_id];
24528     request.dialog_id = dialog_id;
24529     request.message_ids.push_back(m->message_id);
24530     request.is_finished.push_back(false);
24531 
24532     request.results.push_back(Status::OK());
24533   }
24534 
24535   auto content = is_edit ? m->edited_content.get() : m->content.get();
24536   CHECK(content != nullptr);
24537   auto content_type = content->get_type();
24538   if (content_type == MessageContentType::Text) {
24539     CHECK(!is_edit);
24540     send_closure_later(actor_id(this), &MessagesManager::on_text_message_ready_to_send, dialog_id, m->message_id);
24541     return;
24542   }
24543 
24544   FileId file_id = get_message_content_any_file_id(content);  // any_file_id, because it could be a photo sent by ID
24545   FileView file_view = td_->file_manager_->get_file_view(file_id);
24546   FileId thumbnail_file_id = get_message_content_thumbnail_file_id(content, td_);
24547   LOG(DEBUG) << "Need to send file " << file_id << " with thumbnail " << thumbnail_file_id;
24548   if (is_secret) {
24549     CHECK(!is_edit);
24550     auto secret_input_media = get_secret_input_media(content, td_, nullptr, BufferSlice());
24551     if (secret_input_media.empty()) {
24552       LOG(INFO) << "Ask to upload encrypted file " << file_id;
24553       CHECK(file_view.is_encrypted_secret());
24554       CHECK(file_id.is_valid());
24555       CHECK(being_uploaded_files_.find(file_id) == being_uploaded_files_.end());
24556       being_uploaded_files_[file_id] = {FullMessageId(dialog_id, m->message_id), thumbnail_file_id};
24557       // need to call resume_upload synchronously to make upload process consistent with being_uploaded_files_
24558       td_->file_manager_->resume_upload(file_id, std::move(bad_parts), upload_media_callback_, 1, m->message_id.get());
24559     } else {
24560       on_secret_message_media_uploaded(dialog_id, m, std::move(secret_input_media), file_id, thumbnail_file_id);
24561     }
24562   } else {
24563     auto input_media =
24564         get_input_media(content, td_, m->ttl, m->send_emoji, td_->auth_manager_->is_bot() && bad_parts.empty());
24565     if (input_media == nullptr) {
24566       if (content_type == MessageContentType::Game || content_type == MessageContentType::Poll) {
24567         return;
24568       }
24569       if (content_type == MessageContentType::Photo) {
24570         thumbnail_file_id = FileId();
24571       }
24572 
24573       LOG(INFO) << "Ask to upload file " << file_id << " with bad parts " << bad_parts;
24574       CHECK(file_id.is_valid());
24575       CHECK(being_uploaded_files_.find(file_id) == being_uploaded_files_.end());
24576       being_uploaded_files_[file_id] = {FullMessageId(dialog_id, m->message_id), thumbnail_file_id};
24577       // need to call resume_upload synchronously to make upload process consistent with being_uploaded_files_
24578       td_->file_manager_->resume_upload(file_id, std::move(bad_parts), upload_media_callback_, 1, m->message_id.get());
24579     } else {
24580       on_message_media_uploaded(dialog_id, m, std::move(input_media), file_id, thumbnail_file_id);
24581     }
24582   }
24583 }
24584 
on_message_media_uploaded(DialogId dialog_id,const Message * m,tl_object_ptr<telegram_api::InputMedia> && input_media,FileId file_id,FileId thumbnail_file_id)24585 void MessagesManager::on_message_media_uploaded(DialogId dialog_id, const Message *m,
24586                                                 tl_object_ptr<telegram_api::InputMedia> &&input_media, FileId file_id,
24587                                                 FileId thumbnail_file_id) {
24588   CHECK(m != nullptr);
24589   CHECK(input_media != nullptr);
24590 
24591   auto message_id = m->message_id;
24592   if (message_id.is_any_server()) {
24593     const FormattedText *caption = get_message_content_caption(m->edited_content.get());
24594     auto input_reply_markup = get_input_reply_markup(m->edited_reply_markup);
24595     bool was_uploaded = FileManager::extract_was_uploaded(input_media);
24596     bool was_thumbnail_uploaded = FileManager::extract_was_thumbnail_uploaded(input_media);
24597 
24598     LOG(INFO) << "Edit media from " << message_id << " in " << dialog_id;
24599     auto schedule_date = get_message_schedule_date(m);
24600     auto promise = PromiseCreator::lambda(
24601         [actor_id = actor_id(this), dialog_id, message_id, file_id, thumbnail_file_id, schedule_date,
24602          generation = m->edit_generation, was_uploaded, was_thumbnail_uploaded,
24603          file_reference = FileManager::extract_file_reference(input_media)](Result<int32> result) mutable {
24604           send_closure(actor_id, &MessagesManager::on_message_media_edited, dialog_id, message_id, file_id,
24605                        thumbnail_file_id, was_uploaded, was_thumbnail_uploaded, std::move(file_reference),
24606                        schedule_date, generation, std::move(result));
24607         });
24608     send_closure(td_->create_net_actor<EditMessageActor>(std::move(promise)), &EditMessageActor::send, 1 << 11,
24609                  dialog_id, message_id, caption == nullptr ? "" : caption->text,
24610                  get_input_message_entities(td_->contacts_manager_.get(), caption, "edit_message_media"),
24611                  std::move(input_media), std::move(input_reply_markup), schedule_date,
24612                  get_sequence_dispatcher_id(dialog_id, MessageContentType::None));
24613     return;
24614   }
24615 
24616   if (m->media_album_id == 0) {
24617     send_closure_later(
24618         actor_id(this), &MessagesManager::on_media_message_ready_to_send, dialog_id, message_id,
24619         PromiseCreator::lambda([this, dialog_id, input_media = std::move(input_media), file_id,
24620                                 thumbnail_file_id](Result<Message *> result) mutable {
24621           if (result.is_error() || G()->close_flag()) {
24622             return;
24623           }
24624 
24625           auto m = result.move_as_ok();
24626           CHECK(m != nullptr);
24627           CHECK(input_media != nullptr);
24628 
24629           const FormattedText *caption = get_message_content_caption(m->content.get());
24630           LOG(INFO) << "Send media from " << m->message_id << " in " << dialog_id << " in reply to "
24631                     << m->reply_to_message_id;
24632           int64 random_id = begin_send_message(dialog_id, m);
24633           send_closure(
24634               td_->create_net_actor<SendMediaActor>(), &SendMediaActor::send, file_id, thumbnail_file_id,
24635               get_message_flags(m), dialog_id, get_send_message_as_input_peer(m), m->reply_to_message_id,
24636               get_message_schedule_date(m), get_input_reply_markup(m->reply_markup),
24637               get_input_message_entities(td_->contacts_manager_.get(), caption, "on_message_media_uploaded"),
24638               caption == nullptr ? "" : caption->text, std::move(input_media), random_id, &m->send_query_ref,
24639               get_sequence_dispatcher_id(dialog_id, m->is_copy ? MessageContentType::None : m->content->get_type()));
24640         }));
24641   } else {
24642     switch (input_media->get_id()) {
24643       case telegram_api::inputMediaUploadedDocument::ID:
24644         static_cast<telegram_api::inputMediaUploadedDocument *>(input_media.get())->flags_ |=
24645             telegram_api::inputMediaUploadedDocument::NOSOUND_VIDEO_MASK;
24646       // fallthrough
24647       case telegram_api::inputMediaUploadedPhoto::ID:
24648       case telegram_api::inputMediaDocumentExternal::ID:
24649       case telegram_api::inputMediaPhotoExternal::ID:
24650         LOG(INFO) << "Upload media from " << message_id << " in " << dialog_id;
24651         td_->create_handler<UploadMediaQuery>()->send(dialog_id, message_id, file_id, thumbnail_file_id,
24652                                                       std::move(input_media));
24653         break;
24654       case telegram_api::inputMediaDocument::ID:
24655       case telegram_api::inputMediaPhoto::ID:
24656         send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id,
24657                            dialog_id, message_id, Status::OK());
24658         break;
24659       default:
24660         LOG(ERROR) << "Have wrong input media " << to_string(input_media);
24661         send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id,
24662                            dialog_id, message_id, Status::Error(400, "Invalid input media"));
24663     }
24664   }
24665 }
24666 
on_secret_message_media_uploaded(DialogId dialog_id,const Message * m,SecretInputMedia && secret_input_media,FileId file_id,FileId thumbnail_file_id)24667 void MessagesManager::on_secret_message_media_uploaded(DialogId dialog_id, const Message *m,
24668                                                        SecretInputMedia &&secret_input_media, FileId file_id,
24669                                                        FileId thumbnail_file_id) {
24670   CHECK(m != nullptr);
24671   CHECK(m->message_id.is_valid());
24672   CHECK(!secret_input_media.empty());
24673   /*
24674   if (m->media_album_id != 0) {
24675     switch (secret_input_media->input_file_->get_id()) {
24676       case telegram_api::inputEncryptedFileUploaded::ID:
24677       case telegram_api::inputEncryptedFileBigUploaded::ID:
24678         LOG(INFO) << "Upload media from " << m->message_id << " in " << dialog_id;
24679         return td_->create_handler<UploadEncryptedMediaQuery>()->send(dialog_id, m->message_id, std::move(secret_input_media));
24680       case telegram_api::inputEncryptedFile::ID:
24681         return send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id,
24682                            dialog_id, m->message_id, Status::OK());
24683       default:
24684         LOG(ERROR) << "Have wrong secret input media " << to_string(secret_input_media->input_file_);
24685         return send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id,
24686                            dialog_id, m->message_id, Status::Error(400, "Invalid input media"));
24687   }
24688   */
24689   // TODO use file_id, thumbnail_file_id, was_uploaded, was_thumbnail_uploaded,
24690   // invalidate partial remote location for file_id in case of failed upload even message has already been deleted
24691   send_closure_later(
24692       actor_id(this), &MessagesManager::on_media_message_ready_to_send, dialog_id, m->message_id,
24693       PromiseCreator::lambda(
24694           [this, dialog_id, secret_input_media = std::move(secret_input_media)](Result<Message *> result) mutable {
24695             if (result.is_error() || G()->close_flag()) {
24696               return;
24697             }
24698 
24699             auto m = result.move_as_ok();
24700             CHECK(m != nullptr);
24701             CHECK(!secret_input_media.empty());
24702             LOG(INFO) << "Send secret media from " << m->message_id << " in " << dialog_id << " in reply to "
24703                       << m->reply_to_message_id;
24704             int64 random_id = begin_send_message(dialog_id, m);
24705             auto layer = td_->contacts_manager_->get_secret_chat_layer(dialog_id.get_secret_chat_id());
24706             auto caption = get_message_content_caption(m->content.get());
24707             vector<tl_object_ptr<secret_api::MessageEntity>> entities;
24708             if (caption != nullptr && !caption->entities.empty()) {
24709               entities = get_input_secret_message_entities(caption->entities, layer);
24710             }
24711             send_closure(td_->create_net_actor<SendSecretMessageActor>(), &SendSecretMessageActor::send, dialog_id,
24712                          m->reply_to_random_id, m->ttl, "", std::move(secret_input_media), std::move(entities),
24713                          m->via_bot_user_id, m->media_album_id, m->disable_notification, random_id);
24714           }));
24715 }
24716 
on_upload_message_media_success(DialogId dialog_id,MessageId message_id,tl_object_ptr<telegram_api::MessageMedia> && media)24717 void MessagesManager::on_upload_message_media_success(DialogId dialog_id, MessageId message_id,
24718                                                       tl_object_ptr<telegram_api::MessageMedia> &&media) {
24719   Dialog *d = get_dialog(dialog_id);
24720   CHECK(d != nullptr);
24721 
24722   CHECK(message_id.is_valid() || message_id.is_valid_scheduled());
24723   CHECK(message_id.is_yet_unsent());
24724   Message *m = get_message(d, message_id);
24725   if (m == nullptr) {
24726     // message has already been deleted by the user or sent to inaccessible channel
24727     // don't need to send error to the user, because the message has already been deleted
24728     // and there is nothing to be deleted from the server
24729     LOG(INFO) << "Fail to send already deleted by the user or sent to inaccessible chat "
24730               << FullMessageId{dialog_id, message_id};
24731     return;
24732   }
24733 
24734   if (!have_input_peer(dialog_id, AccessRights::Read)) {
24735     return;  // the message should be deleted soon
24736   }
24737 
24738   auto caption = get_message_content_caption(m->content.get());
24739   auto content = get_message_content(td_, caption == nullptr ? FormattedText() : *caption, std::move(media), dialog_id,
24740                                      false, UserId(), nullptr, nullptr);
24741 
24742   if (update_message_content(dialog_id, m, std::move(content), true, true, true) &&
24743       m->message_id == d->last_message_id) {
24744     send_update_chat_last_message_impl(d, "on_upload_message_media_success");
24745   }
24746 
24747   auto input_media = get_input_media(m->content.get(), td_, m->ttl, m->send_emoji, true);
24748   Status result;
24749   if (input_media == nullptr) {
24750     result = Status::Error(400, "Failed to upload file");
24751   }
24752 
24753   send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id, dialog_id,
24754                      m->message_id, std::move(result));
24755 }
24756 
on_upload_message_media_file_part_missing(DialogId dialog_id,MessageId message_id,int bad_part)24757 void MessagesManager::on_upload_message_media_file_part_missing(DialogId dialog_id, MessageId message_id,
24758                                                                 int bad_part) {
24759   Dialog *d = get_dialog(dialog_id);
24760   CHECK(d != nullptr);
24761 
24762   Message *m = get_message(d, message_id);
24763   if (m == nullptr) {
24764     // message has already been deleted by the user or sent to inaccessible channel
24765     // don't need to send error to the user, because the message has already been deleted
24766     // and there is nothing to be deleted from the server
24767     LOG(INFO) << "Fail to send already deleted by the user or sent to inaccessible chat "
24768               << FullMessageId{dialog_id, message_id};
24769     return;
24770   }
24771 
24772   if (!have_input_peer(dialog_id, AccessRights::Read)) {
24773     // LOG(ERROR) << "Found " << m->message_id << " in inaccessible " << dialog_id;
24774     // dump_debug_message_op(get_dialog(dialog_id), 5);
24775     return;  // the message should be deleted soon
24776   }
24777 
24778   CHECK(dialog_id.get_type() != DialogType::SecretChat);
24779 
24780   do_send_message(dialog_id, m, {bad_part});
24781 }
24782 
on_upload_message_media_fail(DialogId dialog_id,MessageId message_id,Status error)24783 void MessagesManager::on_upload_message_media_fail(DialogId dialog_id, MessageId message_id, Status error) {
24784   Dialog *d = get_dialog(dialog_id);
24785   CHECK(d != nullptr);
24786 
24787   Message *m = get_message(d, message_id);
24788   if (m == nullptr) {
24789     // message has already been deleted by the user or sent to inaccessible channel
24790     // don't need to send error to the user, because the message has already been deleted
24791     // and there is nothing to be deleted from the server
24792     LOG(INFO) << "Fail to send already deleted by the user or sent to inaccessible chat "
24793               << FullMessageId{dialog_id, message_id};
24794     return;
24795   }
24796 
24797   if (!have_input_peer(dialog_id, AccessRights::Read)) {
24798     // LOG(ERROR) << "Found " << m->message_id << " in inaccessible " << dialog_id;
24799     // dump_debug_message_op(get_dialog(dialog_id), 5);
24800     return;  // the message should be deleted soon
24801   }
24802 
24803   CHECK(dialog_id.get_type() != DialogType::SecretChat);
24804 
24805   send_closure_later(actor_id(this), &MessagesManager::on_upload_message_media_finished, m->media_album_id, dialog_id,
24806                      m->message_id, std::move(error));
24807 }
24808 
on_upload_message_media_finished(int64 media_album_id,DialogId dialog_id,MessageId message_id,Status result)24809 void MessagesManager::on_upload_message_media_finished(int64 media_album_id, DialogId dialog_id, MessageId message_id,
24810                                                        Status result) {
24811   CHECK(media_album_id < 0);
24812   auto it = pending_message_group_sends_.find(media_album_id);
24813   if (it == pending_message_group_sends_.end()) {
24814     // the group may be already sent or failed to be sent
24815     return;
24816   }
24817   auto &request = it->second;
24818   CHECK(request.dialog_id == dialog_id);
24819   auto message_it = std::find(request.message_ids.begin(), request.message_ids.end(), message_id);
24820   if (message_it == request.message_ids.end()) {
24821     // the message may be already deleted and the album is recreated without it
24822     CHECK(message_id.is_yet_unsent());
24823     LOG_CHECK(get_message({dialog_id, message_id}) == nullptr)
24824         << dialog_id << ' ' << request.message_ids << ' ' << message_id << ' ' << request.finished_count << ' '
24825         << request.is_finished << ' ' << request.results;
24826     return;
24827   }
24828   auto pos = static_cast<size_t>(message_it - request.message_ids.begin());
24829 
24830   if (request.is_finished[pos]) {
24831     LOG(INFO) << "Upload media of " << message_id << " in " << dialog_id << " from group " << media_album_id
24832               << " at pos " << pos << " was already finished";
24833     return;
24834   }
24835   LOG(INFO) << "Finish to upload media of " << message_id << " in " << dialog_id << " from group " << media_album_id
24836             << " at pos " << pos << " with result " << result
24837             << " and previous finished_count = " << request.finished_count;
24838 
24839   request.results[pos] = std::move(result);
24840   request.is_finished[pos] = true;
24841   request.finished_count++;
24842 
24843   if (request.finished_count == request.message_ids.size() || request.results[pos].is_error()) {
24844     // must use send_closure_later if some messages may be being deleted now
24845     // but this function is called only through send_closure_later, so there should be no being deleted messages
24846     // we must use synchronous calls to keep the correct message order during copying of multiple messages
24847     // but "request" iterator can be invalidated by do_send_message_group, so it must not be used below
24848     auto message_ids = request.message_ids;
24849     for (auto request_message_id : message_ids) {
24850       LOG(INFO) << "Send on_media_message_ready_to_send for " << request_message_id << " in " << dialog_id;
24851       auto promise = PromiseCreator::lambda([this, media_album_id](Result<Message *> result) {
24852         if (result.is_error() || G()->close_flag()) {
24853           return;
24854         }
24855 
24856         auto m = result.move_as_ok();
24857         CHECK(m != nullptr);
24858         CHECK(m->media_album_id == media_album_id);
24859         do_send_message_group(media_album_id);
24860         // send_closure_later(actor_id, &MessagesManager::do_send_message_group, media_album_id);
24861       });
24862       // send_closure_later(actor_id(this), &MessagesManager::on_media_message_ready_to_send, dialog_id,
24863       //                   request_message_id, std::move(promise));
24864       on_media_message_ready_to_send(dialog_id, request_message_id, std::move(promise));
24865     }
24866   }
24867 }
24868 
do_send_message_group(int64 media_album_id)24869 void MessagesManager::do_send_message_group(int64 media_album_id) {
24870   CHECK(media_album_id < 0);
24871   auto it = pending_message_group_sends_.find(media_album_id);
24872   if (it == pending_message_group_sends_.end()) {
24873     // the group may be already sent or failed to be sent
24874     return;
24875   }
24876   auto &request = it->second;
24877 
24878   auto dialog_id = request.dialog_id;
24879   Dialog *d = get_dialog(dialog_id);
24880   CHECK(d != nullptr);
24881 
24882   auto default_status = can_send_message(dialog_id);
24883   bool success = default_status.is_ok();
24884   vector<FileId> file_ids;
24885   vector<int64> random_ids;
24886   vector<tl_object_ptr<telegram_api::inputSingleMedia>> input_single_media;
24887   tl_object_ptr<telegram_api::InputPeer> as_input_peer;
24888   MessageId reply_to_message_id;
24889   int32 flags = 0;
24890   int32 schedule_date = 0;
24891   bool is_copy = false;
24892   for (size_t i = 0; i < request.message_ids.size(); i++) {
24893     auto *m = get_message(d, request.message_ids[i]);
24894     if (m == nullptr) {
24895       // skip deleted messages
24896       random_ids.push_back(0);
24897       continue;
24898     }
24899 
24900     reply_to_message_id = m->reply_to_message_id;
24901     flags = get_message_flags(m);
24902     schedule_date = get_message_schedule_date(m);
24903     is_copy = m->is_copy;
24904     as_input_peer = get_send_message_as_input_peer(m);
24905 
24906     file_ids.push_back(get_message_content_any_file_id(m->content.get()));
24907     random_ids.push_back(begin_send_message(dialog_id, m));
24908 
24909     LOG(INFO) << "Have file " << file_ids.back() << " in " << m->message_id << " with result " << request.results[i]
24910               << " and is_finished = " << static_cast<bool>(request.is_finished[i]);
24911 
24912     if (request.results[i].is_error() || !request.is_finished[i]) {
24913       success = false;
24914       continue;
24915     }
24916 
24917     const FormattedText *caption = get_message_content_caption(m->content.get());
24918     auto input_media = get_input_media(m->content.get(), td_, m->ttl, m->send_emoji, true);
24919     if (input_media == nullptr) {
24920       // TODO return CHECK
24921       auto file_id = get_message_content_any_file_id(m->content.get());
24922       auto file_view = td_->file_manager_->get_file_view(file_id);
24923       bool has_remote = file_view.has_remote_location();
24924       bool is_web = has_remote ? file_view.remote_location().is_web() : false;
24925       LOG(FATAL) << request.dialog_id << " " << request.finished_count << " " << i << " " << request.message_ids << " "
24926                  << request.is_finished << " " << request.results << " " << m->ttl << " " << has_remote << " "
24927                  << file_view.has_alive_remote_location() << " " << file_view.has_active_upload_remote_location() << " "
24928                  << file_view.has_active_download_remote_location() << " " << file_view.is_encrypted() << " " << is_web
24929                  << " " << file_view.has_url() << " "
24930                  << to_string(get_message_content_object(m->content.get(), td_, dialog_id, m->date,
24931                                                          m->is_content_secret, false, -1));
24932     }
24933     auto entities = get_input_message_entities(td_->contacts_manager_.get(), caption, "do_send_message_group");
24934     int32 input_single_media_flags = 0;
24935     if (!entities.empty()) {
24936       input_single_media_flags |= telegram_api::inputSingleMedia::ENTITIES_MASK;
24937     }
24938 
24939     input_single_media.push_back(make_tl_object<telegram_api::inputSingleMedia>(
24940         input_single_media_flags, std::move(input_media), random_ids.back(), caption == nullptr ? "" : caption->text,
24941         std::move(entities)));
24942   }
24943 
24944   if (!success) {
24945     if (default_status.is_ok()) {
24946       default_status = Status::Error(400, "Group send failed");
24947     }
24948     for (size_t i = 0; i < random_ids.size(); i++) {
24949       if (random_ids[i] != 0) {
24950         on_send_message_fail(random_ids[i],
24951                              request.results[i].is_error() ? std::move(request.results[i]) : default_status.clone());
24952       }
24953     }
24954     pending_message_group_sends_.erase(it);
24955     return;
24956   }
24957   LOG_CHECK(request.finished_count == request.message_ids.size())
24958       << request.finished_count << " " << request.message_ids.size();
24959   pending_message_group_sends_.erase(it);
24960 
24961   LOG(INFO) << "Begin to send media group " << media_album_id << " to " << dialog_id;
24962 
24963   if (input_single_media.empty()) {
24964     LOG(INFO) << "Media group " << media_album_id << " from " << dialog_id << " is empty";
24965   }
24966   send_closure(td_->create_net_actor<SendMultiMediaActor>(), &SendMultiMediaActor::send, flags, dialog_id,
24967                std::move(as_input_peer), reply_to_message_id, schedule_date, std::move(file_ids),
24968                std::move(input_single_media),
24969                get_sequence_dispatcher_id(dialog_id, is_copy ? MessageContentType::None : MessageContentType::Photo));
24970 }
24971 
on_text_message_ready_to_send(DialogId dialog_id,MessageId message_id)24972 void MessagesManager::on_text_message_ready_to_send(DialogId dialog_id, MessageId message_id) {
24973   LOG(INFO) << "Ready to send " << message_id << " to " << dialog_id;
24974 
24975   auto m = get_message({dialog_id, message_id});
24976   if (m == nullptr) {
24977     return;
24978   }
24979 
24980   CHECK(message_id.is_yet_unsent());
24981 
24982   auto content = m->content.get();
24983   CHECK(content != nullptr);
24984   auto content_type = content->get_type();
24985 
24986   const FormattedText *message_text = get_message_content_text(content);
24987   CHECK(message_text != nullptr);
24988 
24989   int64 random_id = begin_send_message(dialog_id, m);
24990   if (dialog_id.get_type() == DialogType::SecretChat) {
24991     CHECK(!message_id.is_scheduled());
24992     auto layer = td_->contacts_manager_->get_secret_chat_layer(dialog_id.get_secret_chat_id());
24993     send_closure(td_->create_net_actor<SendSecretMessageActor>(), &SendSecretMessageActor::send, dialog_id,
24994                  m->reply_to_random_id, m->ttl, message_text->text,
24995                  get_secret_input_media(content, td_, nullptr, BufferSlice()),
24996                  get_input_secret_message_entities(message_text->entities, layer), m->via_bot_user_id,
24997                  m->media_album_id, m->disable_notification, random_id);
24998   } else {
24999     send_closure(td_->create_net_actor<SendMessageActor>(), &SendMessageActor::send, get_message_flags(m), dialog_id,
25000                  get_send_message_as_input_peer(m), m->reply_to_message_id, get_message_schedule_date(m),
25001                  get_input_reply_markup(m->reply_markup),
25002                  get_input_message_entities(td_->contacts_manager_.get(), message_text->entities, "do_send_message"),
25003                  message_text->text, random_id, &m->send_query_ref,
25004                  get_sequence_dispatcher_id(dialog_id, content_type));
25005   }
25006 }
25007 
on_media_message_ready_to_send(DialogId dialog_id,MessageId message_id,Promise<Message * > && promise)25008 void MessagesManager::on_media_message_ready_to_send(DialogId dialog_id, MessageId message_id,
25009                                                      Promise<Message *> &&promise) {
25010   LOG(INFO) << "Ready to send " << message_id << " to " << dialog_id;
25011   CHECK(promise);
25012   if (!G()->parameters().use_file_db || message_id.is_scheduled()) {  // ResourceManager::Mode::Greedy
25013     auto m = get_message({dialog_id, message_id});
25014     if (m != nullptr) {
25015       promise.set_value(std::move(m));
25016     }
25017     return;
25018   }
25019 
25020   auto queue_id = get_sequence_dispatcher_id(dialog_id, MessageContentType::Photo);
25021   CHECK(queue_id & 1);
25022   auto &queue = yet_unsent_media_queues_[queue_id];
25023   auto it = queue.find(message_id);
25024   if (it == queue.end()) {
25025     if (queue.empty()) {
25026       yet_unsent_media_queues_.erase(queue_id);
25027     }
25028 
25029     LOG(INFO) << "Can't find " << message_id << " in the queue of " << dialog_id;
25030     auto m = get_message({dialog_id, message_id});
25031     if (m != nullptr) {
25032       promise.set_value(std::move(m));
25033     }
25034     return;
25035   }
25036   if (it->second) {
25037     promise.set_error(Status::Error(500, "Duplicate promise"));
25038     return;
25039   }
25040   it->second = std::move(promise);
25041 
25042   on_yet_unsent_media_queue_updated(dialog_id);
25043 }
25044 
on_yet_unsent_media_queue_updated(DialogId dialog_id)25045 void MessagesManager::on_yet_unsent_media_queue_updated(DialogId dialog_id) {
25046   auto queue_id = get_sequence_dispatcher_id(dialog_id, MessageContentType::Photo);
25047   CHECK(queue_id & 1);
25048   while (true) {
25049     auto it = yet_unsent_media_queues_.find(queue_id);
25050     if (it == yet_unsent_media_queues_.end()) {
25051       return;
25052     }
25053     auto &queue = it->second;
25054     if (queue.empty()) {
25055       yet_unsent_media_queues_.erase(it);
25056       return;
25057     }
25058     auto first_it = queue.begin();
25059     if (!first_it->second) {
25060       return;
25061     }
25062 
25063     auto m = get_message({dialog_id, first_it->first});
25064     auto promise = std::move(first_it->second);
25065     queue.erase(first_it);
25066     LOG(INFO) << "Queue for " << dialog_id << " now has size " << queue.size();
25067 
25068     // don't use it/queue/first_it after promise is called
25069     if (m != nullptr) {
25070       LOG(INFO) << "Can send " << FullMessageId{dialog_id, m->message_id};
25071       promise.set_value(std::move(m));
25072     } else {
25073       promise.set_error(Status::Error(400, "Message not found"));
25074     }
25075   }
25076 }
25077 
send_bot_start_message(UserId bot_user_id,DialogId dialog_id,const string & parameter)25078 Result<MessageId> MessagesManager::send_bot_start_message(UserId bot_user_id, DialogId dialog_id,
25079                                                           const string &parameter) {
25080   LOG(INFO) << "Begin to send bot start message to " << dialog_id;
25081   if (td_->auth_manager_->is_bot()) {
25082     return Status::Error(400, "Bot can't send start message to another bot");
25083   }
25084 
25085   TRY_RESULT(bot_data, td_->contacts_manager_->get_bot_data(bot_user_id));
25086 
25087   Dialog *d = get_dialog_force(dialog_id, "send_bot_start_message");
25088   if (d == nullptr) {
25089     return Status::Error(400, "Chat not found");
25090   }
25091 
25092   bool is_chat_with_bot = false;
25093   switch (dialog_id.get_type()) {
25094     case DialogType::User:
25095       if (dialog_id.get_user_id() != bot_user_id) {
25096         return Status::Error(400, "Can't send start message to a private chat other than chat with the bot");
25097       }
25098       is_chat_with_bot = true;
25099       break;
25100     case DialogType::Chat: {
25101       if (!bot_data.can_join_groups) {
25102         return Status::Error(400, "Bot can't join groups");
25103       }
25104 
25105       auto chat_id = dialog_id.get_chat_id();
25106       if (!td_->contacts_manager_->have_input_peer_chat(chat_id, AccessRights::Write)) {
25107         return Status::Error(400, "Can't access the chat");
25108       }
25109       auto status = td_->contacts_manager_->get_chat_permissions(chat_id);
25110       if (!status.can_invite_users()) {
25111         return Status::Error(400, "Need administrator rights to invite a bot to the group chat");
25112       }
25113       break;
25114     }
25115     case DialogType::Channel: {
25116       auto channel_id = dialog_id.get_channel_id();
25117       if (!td_->contacts_manager_->have_input_peer_channel(channel_id, AccessRights::Write)) {
25118         return Status::Error(400, "Can't access the chat");
25119       }
25120       switch (td_->contacts_manager_->get_channel_type(channel_id)) {
25121         case ContactsManager::ChannelType::Megagroup:
25122           if (!bot_data.can_join_groups) {
25123             return Status::Error(400, "The bot can't join groups");
25124           }
25125           break;
25126         case ContactsManager::ChannelType::Broadcast:
25127           return Status::Error(400, "Bots can't be invited to channel chats. Add them as administrators instead");
25128         case ContactsManager::ChannelType::Unknown:
25129         default:
25130           UNREACHABLE();
25131       }
25132       auto status = td_->contacts_manager_->get_channel_permissions(channel_id);
25133       if (!status.can_invite_users()) {
25134         return Status::Error(400, "Need administrator rights to invite a bot to the supergroup chat");
25135       }
25136       break;
25137     }
25138     case DialogType::SecretChat:
25139       return Status::Error(400, "Can't send bot start message to a secret chat");
25140     case DialogType::None:
25141     default:
25142       UNREACHABLE();
25143   }
25144   string text = "/start";
25145   if (!is_chat_with_bot) {
25146     text += '@';
25147     text += bot_data.username;
25148   }
25149 
25150   vector<MessageEntity> text_entities;
25151   text_entities.emplace_back(MessageEntity::Type::BotCommand, 0, narrow_cast<int32>(text.size()));
25152   bool need_update_dialog_pos = false;
25153   Message *m = get_message_to_send(d, MessageId(), MessageId(), MessageSendOptions(),
25154                                    create_text_message_content(text, std::move(text_entities), WebPageId()),
25155                                    &need_update_dialog_pos);
25156   m->is_bot_start_message = true;
25157 
25158   send_update_new_message(d, m);
25159   if (need_update_dialog_pos) {
25160     send_update_chat_last_message(d, "send_bot_start_message");
25161   }
25162 
25163   if (parameter.empty() && is_chat_with_bot) {
25164     save_send_message_log_event(dialog_id, m);
25165     do_send_message(dialog_id, m);
25166   } else {
25167     save_send_bot_start_message_log_event(bot_user_id, dialog_id, parameter, m);
25168     do_send_bot_start_message(bot_user_id, dialog_id, parameter, m);
25169   }
25170   return m->message_id;
25171 }
25172 
25173 class MessagesManager::SendBotStartMessageLogEvent {
25174  public:
25175   UserId bot_user_id;
25176   DialogId dialog_id;
25177   string parameter;
25178   const Message *m_in = nullptr;
25179   unique_ptr<Message> m_out;
25180 
25181   template <class StorerT>
store(StorerT & storer) const25182   void store(StorerT &storer) const {
25183     td::store(bot_user_id, storer);
25184     td::store(dialog_id, storer);
25185     td::store(parameter, storer);
25186     td::store(*m_in, storer);
25187   }
25188 
25189   template <class ParserT>
parse(ParserT & parser)25190   void parse(ParserT &parser) {
25191     td::parse(bot_user_id, parser);
25192     td::parse(dialog_id, parser);
25193     td::parse(parameter, parser);
25194     td::parse(m_out, parser);
25195   }
25196 };
25197 
save_send_bot_start_message_log_event(UserId bot_user_id,DialogId dialog_id,const string & parameter,const Message * m)25198 void MessagesManager::save_send_bot_start_message_log_event(UserId bot_user_id, DialogId dialog_id,
25199                                                             const string &parameter, const Message *m) {
25200   if (!G()->parameters().use_message_db) {
25201     return;
25202   }
25203 
25204   CHECK(m != nullptr);
25205   LOG(INFO) << "Save " << FullMessageId(dialog_id, m->message_id) << " to binlog";
25206   SendBotStartMessageLogEvent log_event;
25207   log_event.bot_user_id = bot_user_id;
25208   log_event.dialog_id = dialog_id;
25209   log_event.parameter = parameter;
25210   log_event.m_in = m;
25211   CHECK(m->send_message_log_event_id == 0);
25212   m->send_message_log_event_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::SendBotStartMessage,
25213                                             get_log_event_storer(log_event));
25214 }
25215 
do_send_bot_start_message(UserId bot_user_id,DialogId dialog_id,const string & parameter,const Message * m)25216 void MessagesManager::do_send_bot_start_message(UserId bot_user_id, DialogId dialog_id, const string &parameter,
25217                                                 const Message *m) {
25218   LOG(INFO) << "Do send bot start " << FullMessageId(dialog_id, m->message_id) << " to bot " << bot_user_id;
25219 
25220   int64 random_id = begin_send_message(dialog_id, m);
25221   telegram_api::object_ptr<telegram_api::InputPeer> input_peer = dialog_id.get_type() == DialogType::User
25222                                                                      ? make_tl_object<telegram_api::inputPeerEmpty>()
25223                                                                      : get_input_peer(dialog_id, AccessRights::Write);
25224   if (input_peer == nullptr) {
25225     return on_send_message_fail(random_id, Status::Error(400, "Have no info about the chat"));
25226   }
25227   auto bot_input_user = td_->contacts_manager_->get_input_user(bot_user_id);
25228   if (bot_input_user == nullptr) {
25229     return on_send_message_fail(random_id, Status::Error(400, "Have no info about the bot"));
25230   }
25231 
25232   m->send_query_ref = td_->create_handler<StartBotQuery>()->send(std::move(bot_input_user), dialog_id,
25233                                                                  std::move(input_peer), parameter, random_id);
25234 }
25235 
send_inline_query_result_message(DialogId dialog_id,MessageId top_thread_message_id,MessageId reply_to_message_id,tl_object_ptr<td_api::messageSendOptions> && options,int64 query_id,const string & result_id,bool hide_via_bot)25236 Result<MessageId> MessagesManager::send_inline_query_result_message(DialogId dialog_id, MessageId top_thread_message_id,
25237                                                                     MessageId reply_to_message_id,
25238                                                                     tl_object_ptr<td_api::messageSendOptions> &&options,
25239                                                                     int64 query_id, const string &result_id,
25240                                                                     bool hide_via_bot) {
25241   LOG(INFO) << "Begin to send inline query result message to " << dialog_id << " in reply to " << reply_to_message_id;
25242 
25243   Dialog *d = get_dialog_force(dialog_id, "send_inline_query_result_message");
25244   if (d == nullptr) {
25245     return Status::Error(400, "Chat not found");
25246   }
25247 
25248   TRY_STATUS(can_send_message(dialog_id));
25249   TRY_RESULT(message_send_options, process_message_send_options(dialog_id, std::move(options)));
25250   bool to_secret = false;
25251   switch (dialog_id.get_type()) {
25252     case DialogType::User:
25253     case DialogType::Chat:
25254       // ok
25255       break;
25256     case DialogType::Channel: {
25257       auto channel_status = td_->contacts_manager_->get_channel_permissions(dialog_id.get_channel_id());
25258       if (!channel_status.can_use_inline_bots()) {
25259         return Status::Error(400, "Can't use inline bots in the chat");
25260       }
25261       break;
25262     }
25263     case DialogType::SecretChat:
25264       to_secret = true;
25265       // ok
25266       break;
25267     case DialogType::None:
25268     default:
25269       UNREACHABLE();
25270   }
25271 
25272   const InlineMessageContent *content = td_->inline_queries_manager_->get_inline_message_content(query_id, result_id);
25273   if (content == nullptr) {
25274     return Status::Error(400, "Inline query result not found");
25275   }
25276 
25277   reply_to_message_id = get_reply_to_message_id(d, top_thread_message_id, reply_to_message_id, false);
25278   TRY_STATUS(can_use_message_send_options(message_send_options, content->message_content, 0));
25279   TRY_STATUS(can_send_message_content(dialog_id, content->message_content.get(), false, td_));
25280   TRY_STATUS(can_use_top_thread_message_id(d, top_thread_message_id, reply_to_message_id));
25281 
25282   bool need_update_dialog_pos = false;
25283   Message *m = get_message_to_send(d, top_thread_message_id, reply_to_message_id, message_send_options,
25284                                    dup_message_content(td_, dialog_id, content->message_content.get(),
25285                                                        MessageContentDupType::SendViaBot, MessageCopyOptions()),
25286                                    &need_update_dialog_pos, false, nullptr, true);
25287   m->hide_via_bot = hide_via_bot;
25288   if (!hide_via_bot) {
25289     m->via_bot_user_id = td_->inline_queries_manager_->get_inline_bot_user_id(query_id);
25290   }
25291   if (content->message_reply_markup != nullptr && !to_secret) {
25292     m->reply_markup = make_unique<ReplyMarkup>(*content->message_reply_markup);
25293   }
25294   m->disable_web_page_preview = content->disable_web_page_preview;
25295   m->clear_draft = true;
25296 
25297   if (top_thread_message_id.is_valid()) {
25298     set_dialog_draft_message(dialog_id, top_thread_message_id, nullptr).ignore();
25299   } else {
25300     update_dialog_draft_message(d, nullptr, false, !need_update_dialog_pos);
25301   }
25302 
25303   send_update_new_message(d, m);
25304   if (need_update_dialog_pos) {
25305     send_update_chat_last_message(d, "send_inline_query_result_message");
25306   }
25307 
25308   if (to_secret) {
25309     save_send_message_log_event(dialog_id, m);
25310     do_send_message(dialog_id, m);
25311     return m->message_id;
25312   }
25313 
25314   save_send_inline_query_result_message_log_event(dialog_id, m, query_id, result_id);
25315   do_send_inline_query_result_message(dialog_id, m, query_id, result_id);
25316   return m->message_id;
25317 }
25318 
25319 class MessagesManager::SendInlineQueryResultMessageLogEvent {
25320  public:
25321   DialogId dialog_id;
25322   int64 query_id;
25323   string result_id;
25324   const Message *m_in = nullptr;
25325   unique_ptr<Message> m_out;
25326 
25327   template <class StorerT>
store(StorerT & storer) const25328   void store(StorerT &storer) const {
25329     td::store(dialog_id, storer);
25330     td::store(query_id, storer);
25331     td::store(result_id, storer);
25332     td::store(*m_in, storer);
25333   }
25334 
25335   template <class ParserT>
parse(ParserT & parser)25336   void parse(ParserT &parser) {
25337     td::parse(dialog_id, parser);
25338     td::parse(query_id, parser);
25339     td::parse(result_id, parser);
25340     td::parse(m_out, parser);
25341   }
25342 };
25343 
save_send_inline_query_result_message_log_event(DialogId dialog_id,const Message * m,int64 query_id,const string & result_id)25344 void MessagesManager::save_send_inline_query_result_message_log_event(DialogId dialog_id, const Message *m,
25345                                                                       int64 query_id, const string &result_id) {
25346   if (!G()->parameters().use_message_db) {
25347     return;
25348   }
25349 
25350   CHECK(m != nullptr);
25351   LOG(INFO) << "Save " << FullMessageId(dialog_id, m->message_id) << " to binlog";
25352   SendInlineQueryResultMessageLogEvent log_event;
25353   log_event.dialog_id = dialog_id;
25354   log_event.query_id = query_id;
25355   log_event.result_id = result_id;
25356   log_event.m_in = m;
25357   CHECK(m->send_message_log_event_id == 0);
25358   m->send_message_log_event_id = binlog_add(
25359       G()->td_db()->get_binlog(), LogEvent::HandlerType::SendInlineQueryResultMessage, get_log_event_storer(log_event));
25360 }
25361 
do_send_inline_query_result_message(DialogId dialog_id,const Message * m,int64 query_id,const string & result_id)25362 void MessagesManager::do_send_inline_query_result_message(DialogId dialog_id, const Message *m, int64 query_id,
25363                                                           const string &result_id) {
25364   LOG(INFO) << "Do send inline query result " << FullMessageId(dialog_id, m->message_id);
25365 
25366   int64 random_id = begin_send_message(dialog_id, m);
25367   auto flags = get_message_flags(m);
25368   if (!m->via_bot_user_id.is_valid() || m->hide_via_bot) {
25369     flags |= telegram_api::messages_sendInlineBotResult::HIDE_VIA_MASK;
25370   }
25371   m->send_query_ref = td_->create_handler<SendInlineBotResultQuery>()->send(
25372       flags, dialog_id, get_send_message_as_input_peer(m), m->reply_to_message_id, get_message_schedule_date(m),
25373       random_id, query_id, result_id);
25374 }
25375 
can_overflow_message_id(DialogId dialog_id)25376 bool MessagesManager::can_overflow_message_id(DialogId dialog_id) {
25377   switch (dialog_id.get_type()) {
25378     case DialogType::User:
25379     case DialogType::Chat:
25380       return G()->shared_config().get_option_integer("session_count") > 1;
25381     case DialogType::Channel:
25382     case DialogType::SecretChat:
25383       return false;
25384     case DialogType::None:
25385     default:
25386       UNREACHABLE();
25387       return false;
25388   }
25389 }
25390 
can_edit_message(DialogId dialog_id,const Message * m,bool is_editing,bool only_reply_markup) const25391 bool MessagesManager::can_edit_message(DialogId dialog_id, const Message *m, bool is_editing,
25392                                        bool only_reply_markup) const {
25393   if (m == nullptr) {
25394     return false;
25395   }
25396   if (m->message_id.is_yet_unsent()) {
25397     return false;
25398   }
25399   if (m->message_id.is_local()) {
25400     return false;
25401   }
25402   if (m->forward_info != nullptr || m->had_forward_info) {
25403     return false;
25404   }
25405 
25406   if (m->had_reply_markup) {
25407     return false;
25408   }
25409   if (m->reply_markup != nullptr && m->reply_markup->type != ReplyMarkup::Type::InlineKeyboard) {
25410     return false;
25411   }
25412 
25413   auto my_id = td_->contacts_manager_->get_my_id();
25414   if (m->via_bot_user_id.is_valid() && (m->via_bot_user_id != my_id || m->message_id.is_scheduled())) {
25415     return false;
25416   }
25417 
25418   bool is_bot = td_->auth_manager_->is_bot();
25419   auto content_type = m->content->get_type();
25420   DialogId my_dialog_id(my_id);
25421   bool has_edit_time_limit = !(is_bot && m->is_outgoing) && dialog_id != my_dialog_id &&
25422                              content_type != MessageContentType::Poll &&
25423                              content_type != MessageContentType::LiveLocation && !m->message_id.is_scheduled();
25424   switch (dialog_id.get_type()) {
25425     case DialogType::User:
25426       if (!m->is_outgoing && dialog_id != my_dialog_id && !m->via_bot_user_id.is_valid()) {
25427         return false;
25428       }
25429       break;
25430     case DialogType::Chat:
25431       if (!m->is_outgoing && !m->via_bot_user_id.is_valid()) {
25432         return false;
25433       }
25434       break;
25435     case DialogType::Channel: {
25436       if (m->via_bot_user_id.is_valid()) {
25437         // outgoing via_bot messages can always be edited
25438         break;
25439       }
25440 
25441       auto channel_id = dialog_id.get_channel_id();
25442       auto channel_status = td_->contacts_manager_->get_channel_permissions(channel_id);
25443       if (m->is_channel_post) {
25444         if (m->message_id.is_scheduled()) {
25445           if (!channel_status.can_post_messages()) {
25446             return false;
25447           }
25448         } else {
25449           if (!channel_status.can_edit_messages() && !(channel_status.can_post_messages() && m->is_outgoing)) {
25450             return false;
25451           }
25452           if (channel_status.can_edit_messages()) {
25453             has_edit_time_limit = false;
25454           }
25455         }
25456         if (is_bot && only_reply_markup) {
25457           has_edit_time_limit = false;
25458         }
25459       } else {
25460         if (!m->is_outgoing) {
25461           return false;
25462         }
25463         if (channel_status.can_pin_messages()) {
25464           has_edit_time_limit = false;
25465         }
25466       }
25467       break;
25468     }
25469     case DialogType::SecretChat:
25470       return false;
25471     case DialogType::None:
25472     default:
25473       UNREACHABLE();
25474       return false;
25475   }
25476 
25477   if (has_edit_time_limit) {
25478     const int32 DEFAULT_EDIT_TIME_LIMIT = 2 * 86400;
25479     int64 edit_time_limit = G()->shared_config().get_option_integer("edit_time_limit", DEFAULT_EDIT_TIME_LIMIT);
25480     if (G()->unix_time_cached() - m->date - (is_editing ? 300 : 0) >= edit_time_limit) {
25481       return false;
25482     }
25483   }
25484 
25485   switch (content_type) {
25486     case MessageContentType::Animation:
25487     case MessageContentType::Audio:
25488     case MessageContentType::Document:
25489     case MessageContentType::Game:
25490     case MessageContentType::Photo:
25491     case MessageContentType::Text:
25492     case MessageContentType::Video:
25493     case MessageContentType::VoiceNote:
25494       return true;
25495     case MessageContentType::LiveLocation: {
25496       if (is_bot && only_reply_markup) {
25497         // there is no caption to edit, but bot can edit inline reply_markup
25498         return true;
25499       }
25500       return G()->unix_time_cached() - m->date < get_message_content_live_location_period(m->content.get());
25501     }
25502     case MessageContentType::Poll: {
25503       if (is_bot && only_reply_markup) {
25504         // there is no caption to edit, but bot can edit inline reply_markup
25505         return true;
25506       }
25507       if (m->message_id.is_scheduled()) {
25508         return false;
25509       }
25510       return !get_message_content_poll_is_closed(td_, m->content.get());
25511     }
25512     case MessageContentType::Contact:
25513     case MessageContentType::Dice:
25514     case MessageContentType::Location:
25515     case MessageContentType::Sticker:
25516     case MessageContentType::Venue:
25517     case MessageContentType::VideoNote:
25518       // there is no caption to edit, but bot can edit inline reply_markup
25519       return is_bot && only_reply_markup;
25520     case MessageContentType::Invoice:
25521     case MessageContentType::Unsupported:
25522     case MessageContentType::ChatCreate:
25523     case MessageContentType::ChatChangeTitle:
25524     case MessageContentType::ChatChangePhoto:
25525     case MessageContentType::ChatDeletePhoto:
25526     case MessageContentType::ChatDeleteHistory:
25527     case MessageContentType::ChatAddUsers:
25528     case MessageContentType::ChatJoinedByLink:
25529     case MessageContentType::ChatDeleteUser:
25530     case MessageContentType::ChatMigrateTo:
25531     case MessageContentType::ChannelCreate:
25532     case MessageContentType::ChannelMigrateFrom:
25533     case MessageContentType::PinMessage:
25534     case MessageContentType::GameScore:
25535     case MessageContentType::ScreenshotTaken:
25536     case MessageContentType::ChatSetTtl:
25537     case MessageContentType::Call:
25538     case MessageContentType::PaymentSuccessful:
25539     case MessageContentType::ContactRegistered:
25540     case MessageContentType::ExpiredPhoto:
25541     case MessageContentType::ExpiredVideo:
25542     case MessageContentType::CustomServiceAction:
25543     case MessageContentType::WebsiteConnected:
25544     case MessageContentType::PassportDataSent:
25545     case MessageContentType::PassportDataReceived:
25546     case MessageContentType::ProximityAlertTriggered:
25547     case MessageContentType::GroupCall:
25548     case MessageContentType::InviteToGroupCall:
25549     case MessageContentType::ChatSetTheme:
25550       return false;
25551     default:
25552       UNREACHABLE();
25553   }
25554 
25555   return false;
25556 }
25557 
can_resend_message(const Message * m) const25558 bool MessagesManager::can_resend_message(const Message *m) const {
25559   if (m->send_error_code != 429 && m->send_error_message != "Message is too old to be re-sent automatically" &&
25560       m->send_error_message != "SCHEDULE_TOO_MUCH" && m->send_error_message != "SEND_AS_PEER_INVALID") {
25561     return false;
25562   }
25563   if (m->is_bot_start_message) {
25564     return false;
25565   }
25566   if (m->forward_info != nullptr || m->real_forward_from_dialog_id.is_valid()) {
25567     // TODO implement resending of forwarded messages
25568     return false;
25569   }
25570   auto content_type = m->content->get_type();
25571   if (m->via_bot_user_id.is_valid() || m->hide_via_bot) {
25572     // via bot message
25573     if (!can_have_input_media(td_, m->content.get())) {
25574       return false;
25575     }
25576 
25577     // resend via_bot message as an ordinary message if error code is 429
25578     // TODO support other error codes
25579   }
25580 
25581   if (content_type == MessageContentType::ChatSetTtl || content_type == MessageContentType::ScreenshotTaken) {
25582     // TODO implement resending of ChatSetTtl and ScreenshotTaken messages
25583     return false;
25584   }
25585   return true;
25586 }
25587 
is_group_dialog(DialogId dialog_id) const25588 bool MessagesManager::is_group_dialog(DialogId dialog_id) const {
25589   switch (dialog_id.get_type()) {
25590     case DialogType::Chat:
25591       return true;
25592     case DialogType::Channel:
25593       return td_->contacts_manager_->get_channel_type(dialog_id.get_channel_id()) ==
25594              ContactsManager::ChannelType::Megagroup;
25595     default:
25596       return false;
25597   }
25598 }
25599 
is_broadcast_channel(DialogId dialog_id) const25600 bool MessagesManager::is_broadcast_channel(DialogId dialog_id) const {
25601   if (dialog_id.get_type() != DialogType::Channel) {
25602     return false;
25603   }
25604 
25605   return td_->contacts_manager_->get_channel_type(dialog_id.get_channel_id()) ==
25606          ContactsManager::ChannelType::Broadcast;
25607 }
25608 
is_deleted_secret_chat(DialogId dialog_id) const25609 bool MessagesManager::is_deleted_secret_chat(DialogId dialog_id) const {
25610   return is_deleted_secret_chat(get_dialog(dialog_id));
25611 }
25612 
is_deleted_secret_chat(const Dialog * d) const25613 bool MessagesManager::is_deleted_secret_chat(const Dialog *d) const {
25614   if (d == nullptr) {
25615     return true;
25616   }
25617   if (d->dialog_id.get_type() != DialogType::SecretChat) {
25618     return false;
25619   }
25620 
25621   if (d->order != DEFAULT_ORDER || d->messages != nullptr) {
25622     return false;
25623   }
25624 
25625   auto state = td_->contacts_manager_->get_secret_chat_state(d->dialog_id.get_secret_chat_id());
25626   if (state != SecretChatState::Closed) {
25627     return false;
25628   }
25629 
25630   return true;
25631 }
25632 
get_message_schedule_date(const Message * m)25633 int32 MessagesManager::get_message_schedule_date(const Message *m) {
25634   CHECK(m != nullptr);
25635   if (!m->message_id.is_scheduled()) {
25636     return 0;
25637   }
25638   if (m->edited_schedule_date != 0) {
25639     return m->edited_schedule_date;
25640   }
25641   return m->date;
25642 }
25643 
get_message_original_sender(const Message * m)25644 DialogId MessagesManager::get_message_original_sender(const Message *m) {
25645   CHECK(m != nullptr);
25646   if (m->forward_info != nullptr) {
25647     auto forward_info = m->forward_info.get();
25648     if (forward_info->is_imported || is_forward_info_sender_hidden(forward_info)) {
25649       return DialogId();
25650     }
25651     if (forward_info->message_id.is_valid() || forward_info->sender_dialog_id.is_valid()) {
25652       return forward_info->sender_dialog_id;
25653     }
25654     return DialogId(forward_info->sender_user_id);
25655   }
25656   return get_message_sender(m);
25657 }
25658 
get_message_sender(const Message * m)25659 DialogId MessagesManager::get_message_sender(const Message *m) {
25660   CHECK(m != nullptr);
25661   return m->sender_dialog_id.is_valid() ? m->sender_dialog_id : DialogId(m->sender_user_id);
25662 }
25663 
edit_message_text(FullMessageId full_message_id,tl_object_ptr<td_api::ReplyMarkup> && reply_markup,tl_object_ptr<td_api::InputMessageContent> && input_message_content,Promise<Unit> && promise)25664 void MessagesManager::edit_message_text(FullMessageId full_message_id,
25665                                         tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
25666                                         tl_object_ptr<td_api::InputMessageContent> &&input_message_content,
25667                                         Promise<Unit> &&promise) {
25668   if (input_message_content == nullptr) {
25669     return promise.set_error(Status::Error(400, "Can't edit message without new content"));
25670   }
25671   int32 new_message_content_type = input_message_content->get_id();
25672   if (new_message_content_type != td_api::inputMessageText::ID) {
25673     return promise.set_error(Status::Error(400, "Input message content type must be InputMessageText"));
25674   }
25675 
25676   LOG(INFO) << "Begin to edit text of " << full_message_id;
25677   auto dialog_id = full_message_id.get_dialog_id();
25678   Dialog *d = get_dialog_force(dialog_id, "edit_message_text");
25679   if (d == nullptr) {
25680     return promise.set_error(Status::Error(400, "Chat not found"));
25681   }
25682 
25683   if (!have_input_peer(dialog_id, AccessRights::Edit)) {
25684     return promise.set_error(Status::Error(400, "Can't access the chat"));
25685   }
25686 
25687   const Message *m = get_message_force(d, full_message_id.get_message_id(), "edit_message_text");
25688   if (m == nullptr) {
25689     return promise.set_error(Status::Error(400, "Message not found"));
25690   }
25691 
25692   if (!can_edit_message(dialog_id, m, true)) {
25693     return promise.set_error(Status::Error(400, "Message can't be edited"));
25694   }
25695 
25696   MessageContentType old_message_content_type = m->content->get_type();
25697   if (old_message_content_type != MessageContentType::Text && old_message_content_type != MessageContentType::Game) {
25698     return promise.set_error(Status::Error(400, "There is no text in the message to edit"));
25699   }
25700 
25701   auto r_input_message_text = process_input_message_text(
25702       td_->contacts_manager_.get(), dialog_id, std::move(input_message_content), td_->auth_manager_->is_bot());
25703   if (r_input_message_text.is_error()) {
25704     return promise.set_error(r_input_message_text.move_as_error());
25705   }
25706   InputMessageText input_message_text = r_input_message_text.move_as_ok();
25707 
25708   auto r_new_reply_markup = get_reply_markup(std::move(reply_markup), td_->auth_manager_->is_bot(), true, false,
25709                                              has_message_sender_user_id(dialog_id, m));
25710   if (r_new_reply_markup.is_error()) {
25711     return promise.set_error(r_new_reply_markup.move_as_error());
25712   }
25713   auto input_reply_markup = get_input_reply_markup(r_new_reply_markup.ok());
25714   int32 flags = 0;
25715   if (input_message_text.disable_web_page_preview) {
25716     flags |= SEND_MESSAGE_FLAG_DISABLE_WEB_PAGE_PREVIEW;
25717   }
25718 
25719   send_closure(
25720       td_->create_net_actor<EditMessageActor>(std::move(promise)), &EditMessageActor::send, flags, dialog_id,
25721       m->message_id, input_message_text.text.text,
25722       get_input_message_entities(td_->contacts_manager_.get(), input_message_text.text.entities, "edit_message_text"),
25723       nullptr, std::move(input_reply_markup), get_message_schedule_date(m),
25724       get_sequence_dispatcher_id(dialog_id, MessageContentType::None));
25725 }
25726 
edit_message_live_location(FullMessageId full_message_id,tl_object_ptr<td_api::ReplyMarkup> && reply_markup,tl_object_ptr<td_api::location> && input_location,int32 heading,int32 proximity_alert_radius,Promise<Unit> && promise)25727 void MessagesManager::edit_message_live_location(FullMessageId full_message_id,
25728                                                  tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
25729                                                  tl_object_ptr<td_api::location> &&input_location, int32 heading,
25730                                                  int32 proximity_alert_radius, Promise<Unit> &&promise) {
25731   LOG(INFO) << "Begin to edit live location of " << full_message_id;
25732   auto dialog_id = full_message_id.get_dialog_id();
25733   Dialog *d = get_dialog_force(dialog_id, "edit_message_live_location");
25734   if (d == nullptr) {
25735     return promise.set_error(Status::Error(400, "Chat not found"));
25736   }
25737 
25738   if (!have_input_peer(dialog_id, AccessRights::Edit)) {
25739     return promise.set_error(Status::Error(400, "Can't access the chat"));
25740   }
25741 
25742   const Message *m = get_message_force(d, full_message_id.get_message_id(), "edit_message_live_location");
25743   if (m == nullptr) {
25744     return promise.set_error(Status::Error(400, "Message not found"));
25745   }
25746 
25747   if (!can_edit_message(dialog_id, m, true)) {
25748     return promise.set_error(Status::Error(400, "Message can't be edited"));
25749   }
25750 
25751   MessageContentType old_message_content_type = m->content->get_type();
25752   if (old_message_content_type != MessageContentType::LiveLocation) {
25753     return promise.set_error(Status::Error(400, "There is no live location in the message to edit"));
25754   }
25755   if (m->message_id.is_scheduled()) {
25756     LOG(ERROR) << "Have " << full_message_id << " with live location";
25757     return promise.set_error(Status::Error(400, "Can't edit live location in scheduled message"));
25758   }
25759 
25760   Location location(input_location);
25761   if (location.empty() && input_location != nullptr) {
25762     return promise.set_error(Status::Error(400, "Invalid location specified"));
25763   }
25764 
25765   auto r_new_reply_markup = get_reply_markup(std::move(reply_markup), td_->auth_manager_->is_bot(), true, false,
25766                                              has_message_sender_user_id(dialog_id, m));
25767   if (r_new_reply_markup.is_error()) {
25768     return promise.set_error(r_new_reply_markup.move_as_error());
25769   }
25770   auto input_reply_markup = get_input_reply_markup(r_new_reply_markup.ok());
25771 
25772   int32 flags = 0;
25773   if (location.empty()) {
25774     flags |= telegram_api::inputMediaGeoLive::STOPPED_MASK;
25775   }
25776   if (heading != 0) {
25777     flags |= telegram_api::inputMediaGeoLive::HEADING_MASK;
25778   }
25779   flags |= telegram_api::inputMediaGeoLive::PROXIMITY_NOTIFICATION_RADIUS_MASK;
25780   auto input_media = telegram_api::make_object<telegram_api::inputMediaGeoLive>(
25781       flags, false /*ignored*/, location.get_input_geo_point(), heading, 0, proximity_alert_radius);
25782   send_closure(td_->create_net_actor<EditMessageActor>(std::move(promise)), &EditMessageActor::send, 0, dialog_id,
25783                m->message_id, string(), vector<tl_object_ptr<telegram_api::MessageEntity>>(), std::move(input_media),
25784                std::move(input_reply_markup), get_message_schedule_date(m),
25785                get_sequence_dispatcher_id(dialog_id, MessageContentType::None));
25786 }
25787 
cancel_edit_message_media(DialogId dialog_id,Message * m,Slice error_message)25788 void MessagesManager::cancel_edit_message_media(DialogId dialog_id, Message *m, Slice error_message) {
25789   if (m->edited_content == nullptr) {
25790     return;
25791   }
25792 
25793   cancel_upload_message_content_files(m->edited_content.get());
25794 
25795   m->edited_content = nullptr;
25796   m->edited_reply_markup = nullptr;
25797   m->edit_generation = 0;
25798   m->edit_promise.set_error(Status::Error(400, error_message));
25799 }
25800 
on_message_media_edited(DialogId dialog_id,MessageId message_id,FileId file_id,FileId thumbnail_file_id,bool was_uploaded,bool was_thumbnail_uploaded,string file_reference,int32 schedule_date,uint64 generation,Result<int32> && result)25801 void MessagesManager::on_message_media_edited(DialogId dialog_id, MessageId message_id, FileId file_id,
25802                                               FileId thumbnail_file_id, bool was_uploaded, bool was_thumbnail_uploaded,
25803                                               string file_reference, int32 schedule_date, uint64 generation,
25804                                               Result<int32> &&result) {
25805   // must not run getDifference
25806 
25807   CHECK(message_id.is_any_server());
25808   auto m = get_message({dialog_id, message_id});
25809   if (m == nullptr || m->edit_generation != generation) {
25810     // message is already deleted or was edited again
25811     return;
25812   }
25813 
25814   CHECK(m->edited_content != nullptr);
25815   if (result.is_ok()) {
25816     // message content has already been replaced from updateEdit{Channel,}Message
25817     // need only merge files from edited_content with their uploaded counterparts
25818     // updateMessageContent was already sent and needs to be sent again,
25819     // only if 'i' and 't' sizes from edited_content was added to the photo
25820     auto pts = result.ok();
25821     LOG(INFO) << "Successfully edited " << message_id << " in " << dialog_id << " with pts = " << pts
25822               << " and last edit pts = " << m->last_edit_pts;
25823     std::swap(m->content, m->edited_content);
25824     bool need_send_update_message_content = m->edited_content->get_type() == MessageContentType::Photo &&
25825                                             m->content->get_type() == MessageContentType::Photo;
25826     bool need_merge_files = pts != 0 && pts == m->last_edit_pts;
25827     update_message_content(dialog_id, m, std::move(m->edited_content), need_send_update_message_content,
25828                            need_merge_files, true);
25829   } else {
25830     LOG(INFO) << "Failed to edit " << message_id << " in " << dialog_id << ": " << result.error();
25831     if (was_uploaded) {
25832       if (was_thumbnail_uploaded) {
25833         CHECK(thumbnail_file_id.is_valid());
25834         // always delete partial remote location for the thumbnail, because it can't be reused anyway
25835         td_->file_manager_->delete_partial_remote_location(thumbnail_file_id);
25836       }
25837       CHECK(file_id.is_valid());
25838       auto error_message = result.error().message();
25839       if (begins_with(error_message, "FILE_PART_") && ends_with(error_message, "_MISSING")) {
25840         do_send_message(dialog_id, m, {to_integer<int32>(error_message.substr(10))});
25841         return;
25842       }
25843 
25844       if (result.error().code() != 429 && result.error().code() < 500 && !G()->close_flag()) {
25845         td_->file_manager_->delete_partial_remote_location(file_id);
25846       }
25847     } else if (!td_->auth_manager_->is_bot() && FileReferenceManager::is_file_reference_error(result.error())) {
25848       if (file_id.is_valid()) {
25849         VLOG(file_references) << "Receive " << result.error() << " for " << file_id;
25850         td_->file_manager_->delete_file_reference(file_id, file_reference);
25851         do_send_message(dialog_id, m, {-1});
25852         return;
25853       } else {
25854         LOG(ERROR) << "Receive file reference error, but have no file_id";
25855       }
25856     }
25857 
25858     cancel_upload_message_content_files(m->edited_content.get());
25859 
25860     if (dialog_id.get_type() != DialogType::SecretChat) {
25861       get_message_from_server({dialog_id, m->message_id}, Auto(), "on_message_media_edited");
25862     }
25863   }
25864 
25865   if (m->edited_schedule_date == schedule_date) {
25866     m->edited_schedule_date = 0;
25867   }
25868   m->edited_content = nullptr;
25869   m->edited_reply_markup = nullptr;
25870   m->edit_generation = 0;
25871   if (result.is_ok()) {
25872     m->edit_promise.set_value(Unit());
25873   } else {
25874     m->edit_promise.set_error(result.move_as_error());
25875   }
25876 }
25877 
edit_message_media(FullMessageId full_message_id,tl_object_ptr<td_api::ReplyMarkup> && reply_markup,tl_object_ptr<td_api::InputMessageContent> && input_message_content,Promise<Unit> && promise)25878 void MessagesManager::edit_message_media(FullMessageId full_message_id,
25879                                          tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
25880                                          tl_object_ptr<td_api::InputMessageContent> &&input_message_content,
25881                                          Promise<Unit> &&promise) {
25882   if (input_message_content == nullptr) {
25883     return promise.set_error(Status::Error(400, "Can't edit message without new content"));
25884   }
25885   int32 new_message_content_type = input_message_content->get_id();
25886   if (new_message_content_type != td_api::inputMessageAnimation::ID &&
25887       new_message_content_type != td_api::inputMessageAudio::ID &&
25888       new_message_content_type != td_api::inputMessageDocument::ID &&
25889       new_message_content_type != td_api::inputMessagePhoto::ID &&
25890       new_message_content_type != td_api::inputMessageVideo::ID) {
25891     return promise.set_error(Status::Error(400, "Unsupported input message content type"));
25892   }
25893 
25894   LOG(INFO) << "Begin to edit media of " << full_message_id;
25895   auto dialog_id = full_message_id.get_dialog_id();
25896   Dialog *d = get_dialog_force(dialog_id, "edit_message_media");
25897   if (d == nullptr) {
25898     return promise.set_error(Status::Error(400, "Chat not found"));
25899   }
25900 
25901   if (!have_input_peer(dialog_id, AccessRights::Edit)) {
25902     return promise.set_error(Status::Error(400, "Can't access the chat"));
25903   }
25904 
25905   Message *m = get_message_force(d, full_message_id.get_message_id(), "edit_message_media");
25906   if (m == nullptr) {
25907     return promise.set_error(Status::Error(400, "Message not found"));
25908   }
25909 
25910   if (!can_edit_message(dialog_id, m, true)) {
25911     return promise.set_error(Status::Error(400, "Message can't be edited"));
25912   }
25913   CHECK(m->message_id.is_any_server());
25914 
25915   MessageContentType old_message_content_type = m->content->get_type();
25916   if (old_message_content_type != MessageContentType::Animation &&
25917       old_message_content_type != MessageContentType::Audio &&
25918       old_message_content_type != MessageContentType::Document &&
25919       old_message_content_type != MessageContentType::Photo && old_message_content_type != MessageContentType::Video) {
25920     return promise.set_error(Status::Error(400, "There is no media in the message to edit"));
25921   }
25922   if (m->ttl > 0) {
25923     return promise.set_error(Status::Error(400, "Can't edit media in self-destructing message"));
25924   }
25925 
25926   auto r_input_message_content = process_input_message_content(dialog_id, std::move(input_message_content));
25927   if (r_input_message_content.is_error()) {
25928     return promise.set_error(r_input_message_content.move_as_error());
25929   }
25930   InputMessageContent content = r_input_message_content.move_as_ok();
25931   if (content.ttl > 0) {
25932     return promise.set_error(Status::Error(400, "Can't enable self-destruction for media"));
25933   }
25934 
25935   if (m->media_album_id != 0) {
25936     auto new_content_type = content.content->get_type();
25937     if (old_message_content_type != new_content_type) {
25938       if (!is_allowed_media_group_content(new_content_type)) {
25939         return promise.set_error(Status::Error(400, "Message content type can't be used in an album"));
25940       }
25941       if (is_homogenous_media_group_content(old_message_content_type) ||
25942           is_homogenous_media_group_content(new_content_type)) {
25943         return promise.set_error(Status::Error(400, "Can't change media type in the album"));
25944       }
25945     }
25946   }
25947 
25948   auto r_new_reply_markup = get_reply_markup(std::move(reply_markup), td_->auth_manager_->is_bot(), true, false,
25949                                              has_message_sender_user_id(dialog_id, m));
25950   if (r_new_reply_markup.is_error()) {
25951     return promise.set_error(r_new_reply_markup.move_as_error());
25952   }
25953 
25954   cancel_edit_message_media(dialog_id, m, "Canceled by new editMessageMedia request");
25955 
25956   m->edited_content =
25957       dup_message_content(td_, dialog_id, content.content.get(), MessageContentDupType::Send, MessageCopyOptions());
25958   CHECK(m->edited_content != nullptr);
25959   m->edited_reply_markup = r_new_reply_markup.move_as_ok();
25960   m->edit_generation = ++current_message_edit_generation_;
25961   m->edit_promise = std::move(promise);
25962 
25963   do_send_message(dialog_id, m);
25964 }
25965 
edit_message_caption(FullMessageId full_message_id,tl_object_ptr<td_api::ReplyMarkup> && reply_markup,tl_object_ptr<td_api::formattedText> && input_caption,Promise<Unit> && promise)25966 void MessagesManager::edit_message_caption(FullMessageId full_message_id,
25967                                            tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
25968                                            tl_object_ptr<td_api::formattedText> &&input_caption,
25969                                            Promise<Unit> &&promise) {
25970   LOG(INFO) << "Begin to edit caption of " << full_message_id;
25971 
25972   auto dialog_id = full_message_id.get_dialog_id();
25973   Dialog *d = get_dialog_force(dialog_id, "edit_message_caption");
25974   if (d == nullptr) {
25975     return promise.set_error(Status::Error(400, "Chat not found"));
25976   }
25977 
25978   if (!have_input_peer(dialog_id, AccessRights::Edit)) {
25979     return promise.set_error(Status::Error(400, "Can't access the chat"));
25980   }
25981 
25982   const Message *m = get_message_force(d, full_message_id.get_message_id(), "edit_message_caption");
25983   if (m == nullptr) {
25984     return promise.set_error(Status::Error(400, "Message not found"));
25985   }
25986 
25987   if (!can_edit_message(dialog_id, m, true)) {
25988     return promise.set_error(Status::Error(400, "Message can't be edited"));
25989   }
25990 
25991   if (!can_have_message_content_caption(m->content->get_type())) {
25992     return promise.set_error(Status::Error(400, "There is no caption in the message to edit"));
25993   }
25994 
25995   auto r_caption = process_input_caption(td_->contacts_manager_.get(), dialog_id, std::move(input_caption),
25996                                          td_->auth_manager_->is_bot());
25997   if (r_caption.is_error()) {
25998     return promise.set_error(r_caption.move_as_error());
25999   }
26000   auto caption = r_caption.move_as_ok();
26001 
26002   auto r_new_reply_markup = get_reply_markup(std::move(reply_markup), td_->auth_manager_->is_bot(), true, false,
26003                                              has_message_sender_user_id(dialog_id, m));
26004   if (r_new_reply_markup.is_error()) {
26005     return promise.set_error(r_new_reply_markup.move_as_error());
26006   }
26007   auto input_reply_markup = get_input_reply_markup(r_new_reply_markup.ok());
26008 
26009   send_closure(td_->create_net_actor<EditMessageActor>(std::move(promise)), &EditMessageActor::send, 1 << 11, dialog_id,
26010                m->message_id, caption.text,
26011                get_input_message_entities(td_->contacts_manager_.get(), caption.entities, "edit_message_caption"),
26012                nullptr, std::move(input_reply_markup), get_message_schedule_date(m),
26013                get_sequence_dispatcher_id(dialog_id, MessageContentType::None));
26014 }
26015 
edit_message_reply_markup(FullMessageId full_message_id,tl_object_ptr<td_api::ReplyMarkup> && reply_markup,Promise<Unit> && promise)26016 void MessagesManager::edit_message_reply_markup(FullMessageId full_message_id,
26017                                                 tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
26018                                                 Promise<Unit> &&promise) {
26019   if (!td_->auth_manager_->is_bot()) {
26020     return promise.set_error(Status::Error(400, "Method is available only for bots"));
26021   }
26022 
26023   LOG(INFO) << "Begin to edit reply markup of " << full_message_id;
26024   auto dialog_id = full_message_id.get_dialog_id();
26025   Dialog *d = get_dialog_force(dialog_id, "edit_message_reply_markup");
26026   if (d == nullptr) {
26027     return promise.set_error(Status::Error(400, "Chat not found"));
26028   }
26029 
26030   if (!have_input_peer(dialog_id, AccessRights::Edit)) {
26031     return promise.set_error(Status::Error(400, "Can't access the chat"));
26032   }
26033 
26034   const Message *m = get_message_force(d, full_message_id.get_message_id(), "edit_message_reply_markup");
26035   if (m == nullptr) {
26036     return promise.set_error(Status::Error(400, "Message not found"));
26037   }
26038 
26039   if (!can_edit_message(dialog_id, m, true, true)) {
26040     return promise.set_error(Status::Error(400, "Message can't be edited"));
26041   }
26042 
26043   auto r_new_reply_markup = get_reply_markup(std::move(reply_markup), td_->auth_manager_->is_bot(), true, false,
26044                                              has_message_sender_user_id(dialog_id, m));
26045   if (r_new_reply_markup.is_error()) {
26046     return promise.set_error(r_new_reply_markup.move_as_error());
26047   }
26048   auto input_reply_markup = get_input_reply_markup(r_new_reply_markup.ok());
26049   send_closure(td_->create_net_actor<EditMessageActor>(std::move(promise)), &EditMessageActor::send, 0, dialog_id,
26050                m->message_id, string(), vector<tl_object_ptr<telegram_api::MessageEntity>>(), nullptr,
26051                std::move(input_reply_markup), get_message_schedule_date(m),
26052                get_sequence_dispatcher_id(dialog_id, MessageContentType::None));
26053 }
26054 
edit_inline_message_text(const string & inline_message_id,tl_object_ptr<td_api::ReplyMarkup> && reply_markup,tl_object_ptr<td_api::InputMessageContent> && input_message_content,Promise<Unit> && promise)26055 void MessagesManager::edit_inline_message_text(const string &inline_message_id,
26056                                                tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
26057                                                tl_object_ptr<td_api::InputMessageContent> &&input_message_content,
26058                                                Promise<Unit> &&promise) {
26059   if (!td_->auth_manager_->is_bot()) {
26060     return promise.set_error(Status::Error(400, "Method is available only for bots"));
26061   }
26062 
26063   if (input_message_content == nullptr) {
26064     return promise.set_error(Status::Error(400, "Can't edit message without new content"));
26065   }
26066   int32 new_message_content_type = input_message_content->get_id();
26067   if (new_message_content_type != td_api::inputMessageText::ID) {
26068     return promise.set_error(Status::Error(400, "Input message content type must be InputMessageText"));
26069   }
26070 
26071   auto r_input_message_text = process_input_message_text(
26072       td_->contacts_manager_.get(), DialogId(), std::move(input_message_content), td_->auth_manager_->is_bot());
26073   if (r_input_message_text.is_error()) {
26074     return promise.set_error(r_input_message_text.move_as_error());
26075   }
26076   InputMessageText input_message_text = r_input_message_text.move_as_ok();
26077 
26078   auto r_new_reply_markup = get_reply_markup(std::move(reply_markup), td_->auth_manager_->is_bot(), true, false, true);
26079   if (r_new_reply_markup.is_error()) {
26080     return promise.set_error(r_new_reply_markup.move_as_error());
26081   }
26082 
26083   auto input_bot_inline_message_id = td_->inline_queries_manager_->get_input_bot_inline_message_id(inline_message_id);
26084   if (input_bot_inline_message_id == nullptr) {
26085     return promise.set_error(Status::Error(400, "Invalid inline message identifier specified"));
26086   }
26087 
26088   int32 flags = 0;
26089   if (input_message_text.disable_web_page_preview) {
26090     flags |= SEND_MESSAGE_FLAG_DISABLE_WEB_PAGE_PREVIEW;
26091   }
26092   td_->create_handler<EditInlineMessageQuery>(std::move(promise))
26093       ->send(flags, std::move(input_bot_inline_message_id), input_message_text.text.text,
26094              get_input_message_entities(td_->contacts_manager_.get(), input_message_text.text.entities,
26095                                         "edit_inline_message_text"),
26096              nullptr, get_input_reply_markup(r_new_reply_markup.ok()));
26097 }
26098 
edit_inline_message_live_location(const string & inline_message_id,tl_object_ptr<td_api::ReplyMarkup> && reply_markup,tl_object_ptr<td_api::location> && input_location,int32 heading,int32 proximity_alert_radius,Promise<Unit> && promise)26099 void MessagesManager::edit_inline_message_live_location(const string &inline_message_id,
26100                                                         tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
26101                                                         tl_object_ptr<td_api::location> &&input_location, int32 heading,
26102                                                         int32 proximity_alert_radius, Promise<Unit> &&promise) {
26103   if (!td_->auth_manager_->is_bot()) {
26104     return promise.set_error(Status::Error(400, "Method is available only for bots"));
26105   }
26106 
26107   auto r_new_reply_markup = get_reply_markup(std::move(reply_markup), td_->auth_manager_->is_bot(), true, false, true);
26108   if (r_new_reply_markup.is_error()) {
26109     return promise.set_error(r_new_reply_markup.move_as_error());
26110   }
26111 
26112   auto input_bot_inline_message_id = td_->inline_queries_manager_->get_input_bot_inline_message_id(inline_message_id);
26113   if (input_bot_inline_message_id == nullptr) {
26114     return promise.set_error(Status::Error(400, "Invalid inline message identifier specified"));
26115   }
26116 
26117   Location location(input_location);
26118   if (location.empty() && input_location != nullptr) {
26119     return promise.set_error(Status::Error(400, "Invalid location specified"));
26120   }
26121 
26122   int32 flags = 0;
26123   if (location.empty()) {
26124     flags |= telegram_api::inputMediaGeoLive::STOPPED_MASK;
26125   }
26126   if (heading != 0) {
26127     flags |= telegram_api::inputMediaGeoLive::HEADING_MASK;
26128   }
26129   flags |= telegram_api::inputMediaGeoLive::PROXIMITY_NOTIFICATION_RADIUS_MASK;
26130   auto input_media = telegram_api::make_object<telegram_api::inputMediaGeoLive>(
26131       flags, false /*ignored*/, location.get_input_geo_point(), heading, 0, proximity_alert_radius);
26132   td_->create_handler<EditInlineMessageQuery>(std::move(promise))
26133       ->send(0, std::move(input_bot_inline_message_id), "", vector<tl_object_ptr<telegram_api::MessageEntity>>(),
26134              std::move(input_media), get_input_reply_markup(r_new_reply_markup.ok()));
26135 }
26136 
edit_inline_message_media(const string & inline_message_id,tl_object_ptr<td_api::ReplyMarkup> && reply_markup,tl_object_ptr<td_api::InputMessageContent> && input_message_content,Promise<Unit> && promise)26137 void MessagesManager::edit_inline_message_media(const string &inline_message_id,
26138                                                 tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
26139                                                 tl_object_ptr<td_api::InputMessageContent> &&input_message_content,
26140                                                 Promise<Unit> &&promise) {
26141   if (!td_->auth_manager_->is_bot()) {
26142     return promise.set_error(Status::Error(400, "Method is available only for bots"));
26143   }
26144 
26145   if (input_message_content == nullptr) {
26146     return promise.set_error(Status::Error(400, "Can't edit message without new content"));
26147   }
26148   int32 new_message_content_type = input_message_content->get_id();
26149   if (new_message_content_type != td_api::inputMessageAnimation::ID &&
26150       new_message_content_type != td_api::inputMessageAudio::ID &&
26151       new_message_content_type != td_api::inputMessageDocument::ID &&
26152       new_message_content_type != td_api::inputMessagePhoto::ID &&
26153       new_message_content_type != td_api::inputMessageVideo::ID) {
26154     return promise.set_error(Status::Error(400, "Unsupported input message content type"));
26155   }
26156 
26157   auto r_input_message_content = process_input_message_content(DialogId(), std::move(input_message_content));
26158   if (r_input_message_content.is_error()) {
26159     return promise.set_error(r_input_message_content.move_as_error());
26160   }
26161   InputMessageContent content = r_input_message_content.move_as_ok();
26162   if (content.ttl > 0) {
26163     LOG(ERROR) << "Have message content with TTL " << content.ttl;
26164     return promise.set_error(Status::Error(400, "Can't enable self-destruction for media"));
26165   }
26166 
26167   auto r_new_reply_markup = get_reply_markup(std::move(reply_markup), td_->auth_manager_->is_bot(), true, false, true);
26168   if (r_new_reply_markup.is_error()) {
26169     return promise.set_error(r_new_reply_markup.move_as_error());
26170   }
26171 
26172   auto input_bot_inline_message_id = td_->inline_queries_manager_->get_input_bot_inline_message_id(inline_message_id);
26173   if (input_bot_inline_message_id == nullptr) {
26174     return promise.set_error(Status::Error(400, "Invalid inline message identifier specified"));
26175   }
26176 
26177   auto input_media = get_input_media(content.content.get(), td_, 0, string(), true);
26178   if (input_media == nullptr) {
26179     return promise.set_error(Status::Error(400, "Invalid message content specified"));
26180   }
26181 
26182   const FormattedText *caption = get_message_content_caption(content.content.get());
26183   td_->create_handler<EditInlineMessageQuery>(std::move(promise))
26184       ->send(1 << 11, std::move(input_bot_inline_message_id), caption == nullptr ? "" : caption->text,
26185              get_input_message_entities(td_->contacts_manager_.get(), caption, "edit_inline_message_media"),
26186              std::move(input_media), get_input_reply_markup(r_new_reply_markup.ok()));
26187 }
26188 
edit_inline_message_caption(const string & inline_message_id,tl_object_ptr<td_api::ReplyMarkup> && reply_markup,tl_object_ptr<td_api::formattedText> && input_caption,Promise<Unit> && promise)26189 void MessagesManager::edit_inline_message_caption(const string &inline_message_id,
26190                                                   tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
26191                                                   tl_object_ptr<td_api::formattedText> &&input_caption,
26192                                                   Promise<Unit> &&promise) {
26193   if (!td_->auth_manager_->is_bot()) {
26194     return promise.set_error(Status::Error(400, "Method is available only for bots"));
26195   }
26196 
26197   auto r_caption = process_input_caption(td_->contacts_manager_.get(), DialogId(), std::move(input_caption),
26198                                          td_->auth_manager_->is_bot());
26199   if (r_caption.is_error()) {
26200     return promise.set_error(r_caption.move_as_error());
26201   }
26202   auto caption = r_caption.move_as_ok();
26203 
26204   auto r_new_reply_markup = get_reply_markup(std::move(reply_markup), td_->auth_manager_->is_bot(), true, false, true);
26205   if (r_new_reply_markup.is_error()) {
26206     return promise.set_error(r_new_reply_markup.move_as_error());
26207   }
26208 
26209   auto input_bot_inline_message_id = td_->inline_queries_manager_->get_input_bot_inline_message_id(inline_message_id);
26210   if (input_bot_inline_message_id == nullptr) {
26211     return promise.set_error(Status::Error(400, "Invalid inline message identifier specified"));
26212   }
26213 
26214   td_->create_handler<EditInlineMessageQuery>(std::move(promise))
26215       ->send(1 << 11, std::move(input_bot_inline_message_id), caption.text,
26216              get_input_message_entities(td_->contacts_manager_.get(), caption.entities, "edit_inline_message_caption"),
26217              nullptr, get_input_reply_markup(r_new_reply_markup.ok()));
26218 }
26219 
edit_inline_message_reply_markup(const string & inline_message_id,tl_object_ptr<td_api::ReplyMarkup> && reply_markup,Promise<Unit> && promise)26220 void MessagesManager::edit_inline_message_reply_markup(const string &inline_message_id,
26221                                                        tl_object_ptr<td_api::ReplyMarkup> &&reply_markup,
26222                                                        Promise<Unit> &&promise) {
26223   if (!td_->auth_manager_->is_bot()) {
26224     return promise.set_error(Status::Error(400, "Method is available only for bots"));
26225   }
26226 
26227   auto r_new_reply_markup = get_reply_markup(std::move(reply_markup), td_->auth_manager_->is_bot(), true, false, true);
26228   if (r_new_reply_markup.is_error()) {
26229     return promise.set_error(r_new_reply_markup.move_as_error());
26230   }
26231 
26232   auto input_bot_inline_message_id = td_->inline_queries_manager_->get_input_bot_inline_message_id(inline_message_id);
26233   if (input_bot_inline_message_id == nullptr) {
26234     return promise.set_error(Status::Error(400, "Invalid inline message identifier specified"));
26235   }
26236 
26237   td_->create_handler<EditInlineMessageQuery>(std::move(promise))
26238       ->send(0, std::move(input_bot_inline_message_id), string(), vector<tl_object_ptr<telegram_api::MessageEntity>>(),
26239              nullptr, get_input_reply_markup(r_new_reply_markup.ok()));
26240 }
26241 
edit_message_scheduling_state(FullMessageId full_message_id,td_api::object_ptr<td_api::MessageSchedulingState> && scheduling_state,Promise<Unit> && promise)26242 void MessagesManager::edit_message_scheduling_state(
26243     FullMessageId full_message_id, td_api::object_ptr<td_api::MessageSchedulingState> &&scheduling_state,
26244     Promise<Unit> &&promise) {
26245   auto r_schedule_date = get_message_schedule_date(std::move(scheduling_state));
26246   if (r_schedule_date.is_error()) {
26247     return promise.set_error(r_schedule_date.move_as_error());
26248   }
26249   auto schedule_date = r_schedule_date.move_as_ok();
26250 
26251   LOG(INFO) << "Begin to reschedule " << full_message_id << " to " << schedule_date;
26252 
26253   auto dialog_id = full_message_id.get_dialog_id();
26254   Dialog *d = get_dialog_force(dialog_id, "edit_message_scheduling_state");
26255   if (d == nullptr) {
26256     return promise.set_error(Status::Error(400, "Chat not found"));
26257   }
26258 
26259   if (!have_input_peer(dialog_id, AccessRights::Edit)) {
26260     return promise.set_error(Status::Error(400, "Can't access the chat"));
26261   }
26262 
26263   Message *m = get_message_force(d, full_message_id.get_message_id(), "edit_message_scheduling_state");
26264   if (m == nullptr) {
26265     return promise.set_error(Status::Error(400, "Message not found"));
26266   }
26267 
26268   if (!m->message_id.is_scheduled()) {
26269     return promise.set_error(Status::Error(400, "Message is not scheduled"));
26270   }
26271   if (!m->message_id.is_scheduled_server()) {
26272     return promise.set_error(Status::Error(400, "Can't reschedule the message"));
26273   }
26274 
26275   if (get_message_schedule_date(m) == schedule_date) {
26276     return promise.set_value(Unit());
26277   }
26278   m->edited_schedule_date = schedule_date;
26279 
26280   if (schedule_date > 0) {
26281     send_closure(td_->create_net_actor<EditMessageActor>(std::move(promise)), &EditMessageActor::send, 0, dialog_id,
26282                  m->message_id, string(), vector<tl_object_ptr<telegram_api::MessageEntity>>(), nullptr, nullptr,
26283                  schedule_date, get_sequence_dispatcher_id(dialog_id, MessageContentType::None));
26284   } else {
26285     send_closure(td_->create_net_actor<SendScheduledMessageActor>(std::move(promise)), &SendScheduledMessageActor::send,
26286                  dialog_id, m->message_id, get_sequence_dispatcher_id(dialog_id, MessageContentType::None));
26287   }
26288 }
26289 
is_discussion_message(DialogId dialog_id,const Message * m) const26290 bool MessagesManager::is_discussion_message(DialogId dialog_id, const Message *m) const {
26291   if (m == nullptr || m->forward_info == nullptr) {
26292     return false;
26293   }
26294   if (m->sender_user_id.is_valid()) {
26295     if (!td_->auth_manager_->is_bot() || m->sender_user_id != ContactsManager::get_service_notifications_user_id()) {
26296       return false;
26297     }
26298   }
26299   if (!m->forward_info->from_dialog_id.is_valid() || !m->forward_info->from_message_id.is_valid()) {
26300     return false;
26301   }
26302   if (dialog_id.get_type() != DialogType::Channel || is_broadcast_channel(dialog_id)) {
26303     return false;
26304   }
26305   if (m->forward_info->from_dialog_id == dialog_id) {
26306     return false;
26307   }
26308   if (m->forward_info->from_dialog_id.get_type() != DialogType::Channel) {
26309     return false;
26310   }
26311   return true;
26312 }
26313 
has_message_sender_user_id(DialogId dialog_id,const Message * m) const26314 bool MessagesManager::has_message_sender_user_id(DialogId dialog_id, const Message *m) const {
26315   if (!m->sender_user_id.is_valid()) {
26316     return false;
26317   }
26318   if (td_->auth_manager_->is_bot() && is_discussion_message(dialog_id, m)) {
26319     return false;
26320   }
26321   return true;
26322 }
26323 
get_message_own_max_media_timestamp(const Message * m) const26324 int32 MessagesManager::get_message_own_max_media_timestamp(const Message *m) const {
26325   auto duration = get_message_content_media_duration(m->content.get(), td_);
26326   return duration == 0 ? std::numeric_limits<int32>::max() : duration;
26327 }
26328 
get_message_max_media_timestamp(const Message * m)26329 int32 MessagesManager::get_message_max_media_timestamp(const Message *m) {
26330   return m->max_own_media_timestamp >= 0 ? m->max_own_media_timestamp : m->max_reply_media_timestamp;
26331 }
26332 
update_message_max_reply_media_timestamp(const Dialog * d,Message * m,bool need_send_update_message_content)26333 void MessagesManager::update_message_max_reply_media_timestamp(const Dialog *d, Message *m,
26334                                                                bool need_send_update_message_content) {
26335   if (td_->auth_manager_->is_bot()) {
26336     return;
26337   }
26338 
26339   auto new_max_reply_media_timestamp = -1;
26340   if (m->reply_to_message_id.is_valid()) {
26341     auto replied_m = get_message(d, m->reply_to_message_id);
26342     if (replied_m != nullptr) {
26343       new_max_reply_media_timestamp = get_message_own_max_media_timestamp(replied_m);
26344     } else if (!d->deleted_message_ids.count(m->reply_to_message_id) &&
26345                m->reply_to_message_id > d->last_clear_history_message_id &&
26346                m->reply_to_message_id > d->max_unavailable_message_id) {
26347       // replied message isn't deleted and isn't loaded yet
26348       return;
26349     }
26350   }
26351 
26352   if (m->max_reply_media_timestamp == new_max_reply_media_timestamp) {
26353     return;
26354   }
26355 
26356   LOG(INFO) << "Set max_reply_media_timestamp in " << m->message_id << " in " << d->dialog_id << " to "
26357             << new_max_reply_media_timestamp;
26358   auto old_max_media_timestamp = get_message_max_media_timestamp(m);
26359   m->max_reply_media_timestamp = new_max_reply_media_timestamp;
26360   auto new_max_media_timestamp = get_message_max_media_timestamp(m);
26361   if (need_send_update_message_content && old_max_media_timestamp != new_max_media_timestamp) {
26362     if (old_max_media_timestamp > new_max_media_timestamp) {
26363       std::swap(old_max_media_timestamp, new_max_media_timestamp);
26364     }
26365 
26366     if (has_media_timestamps(get_message_content_text(m->content.get()), old_max_media_timestamp + 1,
26367                              new_max_media_timestamp)) {
26368       send_update_message_content_impl(d->dialog_id, m, "update_message_max_reply_media_timestamp");
26369     }
26370   }
26371 }
26372 
update_message_max_own_media_timestamp(const Dialog * d,Message * m)26373 void MessagesManager::update_message_max_own_media_timestamp(const Dialog *d, Message *m) {
26374   if (td_->auth_manager_->is_bot()) {
26375     return;
26376   }
26377 
26378   auto new_max_own_media_timestamp = get_message_own_max_media_timestamp(m);
26379   if (m->max_own_media_timestamp == new_max_own_media_timestamp) {
26380     return;
26381   }
26382 
26383   LOG(INFO) << "Set max_own_media_timestamp in " << m->message_id << " in " << d->dialog_id << " to "
26384             << new_max_own_media_timestamp;
26385   m->max_own_media_timestamp = new_max_own_media_timestamp;
26386 
26387   update_message_max_reply_media_timestamp_in_replied_messages(d->dialog_id, m->message_id);
26388 }
26389 
update_message_max_reply_media_timestamp_in_replied_messages(DialogId dialog_id,MessageId reply_to_message_id)26390 void MessagesManager::update_message_max_reply_media_timestamp_in_replied_messages(DialogId dialog_id,
26391                                                                                    MessageId reply_to_message_id) {
26392   if (reply_to_message_id.is_scheduled()) {
26393     return;
26394   }
26395   CHECK(reply_to_message_id.is_valid());
26396 
26397   FullMessageId full_message_id{dialog_id, reply_to_message_id};
26398   auto it = replied_by_media_timestamp_messages_.find(full_message_id);
26399   if (it == replied_by_media_timestamp_messages_.end()) {
26400     return;
26401   }
26402 
26403   LOG(INFO) << "Update max_reply_media_timestamp for replies of " << reply_to_message_id << " in " << dialog_id;
26404 
26405   Dialog *d = get_dialog(dialog_id);
26406   CHECK(d != nullptr);
26407   for (auto message_id : it->second) {
26408     auto m = get_message(d, message_id);
26409     CHECK(m != nullptr);
26410     CHECK(m->reply_to_message_id == reply_to_message_id);
26411     update_message_max_reply_media_timestamp(d, m, true);
26412   }
26413 }
26414 
register_message_reply(const Dialog * d,const Message * m)26415 void MessagesManager::register_message_reply(const Dialog *d, const Message *m) {
26416   if (!m->reply_to_message_id.is_valid() || td_->auth_manager_->is_bot()) {
26417     return;
26418   }
26419 
26420   if (has_media_timestamps(get_message_content_text(m->content.get()), 0, std::numeric_limits<int32>::max())) {
26421     LOG(INFO) << "Register " << m->message_id << " in " << d->dialog_id << " as reply to " << m->reply_to_message_id;
26422     FullMessageId full_message_id{d->dialog_id, m->reply_to_message_id};
26423     bool is_inserted = replied_by_media_timestamp_messages_[full_message_id].insert(m->message_id).second;
26424     CHECK(is_inserted);
26425   }
26426 }
26427 
reregister_message_reply(const Dialog * d,const Message * m)26428 void MessagesManager::reregister_message_reply(const Dialog *d, const Message *m) {
26429   if (!m->reply_to_message_id.is_valid() || td_->auth_manager_->is_bot()) {
26430     return;
26431   }
26432 
26433   auto it = replied_by_media_timestamp_messages_.find({d->dialog_id, m->reply_to_message_id});
26434   bool was_registered = it != replied_by_media_timestamp_messages_.end() && it->second.count(m->message_id) > 0;
26435   bool need_register =
26436       has_media_timestamps(get_message_content_text(m->content.get()), 0, std::numeric_limits<int32>::max());
26437   if (was_registered == need_register) {
26438     return;
26439   }
26440   if (was_registered) {
26441     unregister_message_reply(d, m);
26442   } else {
26443     register_message_reply(d, m);
26444   }
26445 }
26446 
unregister_message_reply(const Dialog * d,const Message * m)26447 void MessagesManager::unregister_message_reply(const Dialog *d, const Message *m) {
26448   auto it = replied_by_media_timestamp_messages_.find({d->dialog_id, m->reply_to_message_id});
26449   if (it == replied_by_media_timestamp_messages_.end()) {
26450     return;
26451   }
26452 
26453   auto is_deleted = it->second.erase(m->message_id) > 0;
26454   if (is_deleted) {
26455     LOG(INFO) << "Unregister " << m->message_id << " in " << d->dialog_id << " as reply to " << m->reply_to_message_id;
26456     if (it->second.empty()) {
26457       replied_by_media_timestamp_messages_.erase(it);
26458     }
26459   }
26460 }
26461 
get_message_disable_web_page_preview(const Message * m)26462 bool MessagesManager::get_message_disable_web_page_preview(const Message *m) {
26463   if (m->content->get_type() != MessageContentType::Text) {
26464     return false;
26465   }
26466   if (has_message_content_web_page(m->content.get())) {
26467     return false;
26468   }
26469   return m->disable_web_page_preview;
26470 }
26471 
get_message_flags(const Message * m)26472 int32 MessagesManager::get_message_flags(const Message *m) {
26473   int32 flags = 0;
26474   if (m->reply_to_message_id.is_valid()) {
26475     flags |= SEND_MESSAGE_FLAG_IS_REPLY;
26476   }
26477   if (m->disable_web_page_preview) {
26478     flags |= SEND_MESSAGE_FLAG_DISABLE_WEB_PAGE_PREVIEW;
26479   }
26480   if (m->reply_markup != nullptr) {
26481     flags |= SEND_MESSAGE_FLAG_HAS_REPLY_MARKUP;
26482   }
26483   if (m->disable_notification) {
26484     flags |= SEND_MESSAGE_FLAG_DISABLE_NOTIFICATION;
26485   }
26486   if (m->from_background) {
26487     flags |= SEND_MESSAGE_FLAG_FROM_BACKGROUND;
26488   }
26489   if (m->clear_draft) {
26490     flags |= SEND_MESSAGE_FLAG_CLEAR_DRAFT;
26491   }
26492   if (m->message_id.is_scheduled()) {
26493     flags |= SEND_MESSAGE_FLAG_HAS_SCHEDULE_DATE;
26494   }
26495   return flags;
26496 }
26497 
get_send_message_as_input_peer(const Message * m) const26498 tl_object_ptr<telegram_api::InputPeer> MessagesManager::get_send_message_as_input_peer(const Message *m) const {
26499   if (!m->has_explicit_sender) {
26500     return nullptr;
26501   }
26502   return get_input_peer(get_message_sender(m), AccessRights::Write);
26503 }
26504 
can_set_game_score(FullMessageId full_message_id) const26505 bool MessagesManager::can_set_game_score(FullMessageId full_message_id) const {
26506   return can_set_game_score(full_message_id.get_dialog_id(), get_message(full_message_id));
26507 }
26508 
can_set_game_score(DialogId dialog_id,const Message * m) const26509 bool MessagesManager::can_set_game_score(DialogId dialog_id, const Message *m) const {
26510   if (m == nullptr) {
26511     return false;
26512   }
26513   if (m->content->get_type() != MessageContentType::Game) {
26514     return false;
26515   }
26516   if (m->message_id.is_scheduled()) {
26517     return false;
26518   }
26519   if (m->message_id.is_yet_unsent()) {
26520     return false;
26521   }
26522   if (m->message_id.is_local()) {
26523     return false;
26524   }
26525   if (m->via_bot_user_id.is_valid() && m->via_bot_user_id != td_->contacts_manager_->get_my_id()) {
26526     return false;
26527   }
26528 
26529   if (!td_->auth_manager_->is_bot()) {
26530     return false;
26531   }
26532   if (m->reply_markup == nullptr || m->reply_markup->type != ReplyMarkup::Type::InlineKeyboard ||
26533       m->reply_markup->inline_keyboard.empty()) {
26534     return false;
26535   }
26536 
26537   switch (dialog_id.get_type()) {
26538     case DialogType::User:
26539       if (!m->is_outgoing && dialog_id != get_my_dialog_id()) {
26540         return false;
26541       }
26542       break;
26543     case DialogType::Chat:
26544       if (!m->is_outgoing) {
26545         return false;
26546       }
26547       break;
26548     case DialogType::Channel: {
26549       if (m->via_bot_user_id.is_valid()) {
26550         // outgoing via_bot messages can always be edited
26551         break;
26552       }
26553       auto channel_id = dialog_id.get_channel_id();
26554       auto channel_status = td_->contacts_manager_->get_channel_permissions(channel_id);
26555       if (m->is_channel_post) {
26556         if (!channel_status.can_edit_messages() && !(channel_status.can_post_messages() && m->is_outgoing)) {
26557           return false;
26558         }
26559       } else {
26560         if (!m->is_outgoing) {
26561           return false;
26562         }
26563       }
26564       break;
26565     }
26566     case DialogType::SecretChat:
26567       return false;
26568     case DialogType::None:
26569     default:
26570       UNREACHABLE();
26571       return false;
26572   }
26573 
26574   return true;
26575 }
26576 
is_forward_info_sender_hidden(const MessageForwardInfo * forward_info)26577 bool MessagesManager::is_forward_info_sender_hidden(const MessageForwardInfo *forward_info) {
26578   CHECK(forward_info != nullptr);
26579   if (forward_info->is_imported) {
26580     return false;
26581   }
26582   if (!forward_info->sender_name.empty()) {
26583     return true;
26584   }
26585   DialogId hidden_sender_dialog_id(ChannelId(static_cast<int64>(G()->is_test_dc() ? 10460537 : 1228946795)));
26586   return forward_info->sender_dialog_id == hidden_sender_dialog_id && !forward_info->author_signature.empty() &&
26587          !forward_info->message_id.is_valid();
26588 }
26589 
get_message_forward_info(tl_object_ptr<telegram_api::messageFwdHeader> && forward_header)26590 unique_ptr<MessagesManager::MessageForwardInfo> MessagesManager::get_message_forward_info(
26591     tl_object_ptr<telegram_api::messageFwdHeader> &&forward_header) {
26592   if (forward_header == nullptr) {
26593     return nullptr;
26594   }
26595 
26596   if (forward_header->date_ <= 0) {
26597     LOG(ERROR) << "Wrong date in message forward header: " << oneline(to_string(forward_header));
26598     return nullptr;
26599   }
26600 
26601   auto flags = forward_header->flags_;
26602   DialogId sender_dialog_id;
26603   MessageId message_id;
26604   string author_signature = std::move(forward_header->post_author_);
26605   DialogId from_dialog_id;
26606   MessageId from_message_id;
26607   string sender_name = std::move(forward_header->from_name_);
26608   bool is_imported = forward_header->imported_;
26609   if (forward_header->from_id_ != nullptr) {
26610     sender_dialog_id = DialogId(forward_header->from_id_);
26611     if (!sender_dialog_id.is_valid()) {
26612       LOG(ERROR) << "Receive invalid sender identifier in message forward header: "
26613                  << oneline(to_string(forward_header));
26614       sender_dialog_id = DialogId();
26615     }
26616   }
26617   if ((flags & telegram_api::messageFwdHeader::CHANNEL_POST_MASK) != 0) {
26618     message_id = MessageId(ServerMessageId(forward_header->channel_post_));
26619     if (!message_id.is_valid()) {
26620       LOG(ERROR) << "Receive " << message_id << " in message forward header: " << oneline(to_string(forward_header));
26621       message_id = MessageId();
26622     }
26623   }
26624   if (forward_header->saved_from_peer_ != nullptr) {
26625     from_dialog_id = DialogId(forward_header->saved_from_peer_);
26626     from_message_id = MessageId(ServerMessageId(forward_header->saved_from_msg_id_));
26627     if (!from_dialog_id.is_valid() || !from_message_id.is_valid()) {
26628       LOG(ERROR) << "Receive " << from_message_id << " in " << from_dialog_id
26629                  << " in message forward header: " << oneline(to_string(forward_header));
26630       from_dialog_id = DialogId();
26631       from_message_id = MessageId();
26632     }
26633   }
26634 
26635   UserId sender_user_id;
26636   if (sender_dialog_id.get_type() == DialogType::User) {
26637     sender_user_id = sender_dialog_id.get_user_id();
26638     sender_dialog_id = DialogId();
26639   }
26640   if (!sender_dialog_id.is_valid()) {
26641     if (sender_user_id.is_valid()) {
26642       if (message_id.is_valid()) {
26643         LOG(ERROR) << "Receive non-empty message identifier in message forward header: "
26644                    << oneline(to_string(forward_header));
26645         message_id = MessageId();
26646       }
26647     } else if (sender_name.empty()) {
26648       LOG(ERROR) << "Receive wrong message forward header: " << oneline(to_string(forward_header));
26649       return nullptr;
26650     }
26651   } else if (sender_dialog_id.get_type() != DialogType::Channel) {
26652     LOG(ERROR) << "Receive wrong message forward header with non-channel sender: "
26653                << oneline(to_string(forward_header));
26654     return nullptr;
26655   } else {
26656     auto channel_id = sender_dialog_id.get_channel_id();
26657     LOG_IF(ERROR, td_->contacts_manager_->have_min_channel(channel_id)) << "Receive forward from min " << channel_id;
26658     force_create_dialog(sender_dialog_id, "message forward info", true);
26659     CHECK(!sender_user_id.is_valid());
26660   }
26661   if (from_dialog_id.is_valid()) {
26662     force_create_dialog(from_dialog_id, "message forward from info", true);
26663   }
26664 
26665   return td::make_unique<MessageForwardInfo>(sender_user_id, forward_header->date_, sender_dialog_id, message_id,
26666                                              std::move(author_signature), std::move(sender_name), from_dialog_id,
26667                                              from_message_id, std::move(forward_header->psa_type_), is_imported);
26668 }
26669 
get_message_forward_info_object(const unique_ptr<MessageForwardInfo> & forward_info) const26670 td_api::object_ptr<td_api::messageForwardInfo> MessagesManager::get_message_forward_info_object(
26671     const unique_ptr<MessageForwardInfo> &forward_info) const {
26672   if (forward_info == nullptr) {
26673     return nullptr;
26674   }
26675 
26676   auto origin = [&]() -> td_api::object_ptr<td_api::MessageForwardOrigin> {
26677     if (forward_info->is_imported) {
26678       return td_api::make_object<td_api::messageForwardOriginMessageImport>(forward_info->sender_name);
26679     }
26680     if (is_forward_info_sender_hidden(forward_info.get())) {
26681       return td_api::make_object<td_api::messageForwardOriginHiddenUser>(
26682           forward_info->sender_name.empty() ? forward_info->author_signature : forward_info->sender_name);
26683     }
26684     if (forward_info->message_id.is_valid()) {
26685       return td_api::make_object<td_api::messageForwardOriginChannel>(
26686           forward_info->sender_dialog_id.get(), forward_info->message_id.get(), forward_info->author_signature);
26687     }
26688     if (forward_info->sender_dialog_id.is_valid()) {
26689       return td_api::make_object<td_api::messageForwardOriginChat>(
26690           forward_info->sender_dialog_id.get(),
26691           forward_info->sender_name.empty() ? forward_info->author_signature : forward_info->sender_name);
26692     }
26693     return td_api::make_object<td_api::messageForwardOriginUser>(
26694         td_->contacts_manager_->get_user_id_object(forward_info->sender_user_id, "messageForwardOriginUser"));
26695   }();
26696 
26697   return td_api::make_object<td_api::messageForwardInfo>(std::move(origin), forward_info->date, forward_info->psa_type,
26698                                                          forward_info->from_dialog_id.get(),
26699                                                          forward_info->from_message_id.get());
26700 }
26701 
get_dialog_reply_markup(DialogId dialog_id,tl_object_ptr<td_api::ReplyMarkup> && reply_markup_ptr) const26702 Result<unique_ptr<ReplyMarkup>> MessagesManager::get_dialog_reply_markup(
26703     DialogId dialog_id, tl_object_ptr<td_api::ReplyMarkup> &&reply_markup_ptr) const {
26704   if (reply_markup_ptr == nullptr) {
26705     return nullptr;
26706   }
26707 
26708   auto dialog_type = dialog_id.get_type();
26709   bool is_anonymous = is_anonymous_administrator(dialog_id, nullptr);
26710 
26711   bool only_inline_keyboard = is_anonymous;
26712   bool request_buttons_allowed = dialog_type == DialogType::User;
26713   bool switch_inline_buttons_allowed = !is_anonymous;
26714 
26715   TRY_RESULT(reply_markup,
26716              get_reply_markup(std::move(reply_markup_ptr), td_->auth_manager_->is_bot(), only_inline_keyboard,
26717                               request_buttons_allowed, switch_inline_buttons_allowed));
26718   if (reply_markup == nullptr) {
26719     return nullptr;
26720   }
26721 
26722   switch (dialog_type) {
26723     case DialogType::User:
26724       if (reply_markup->type != ReplyMarkup::Type::InlineKeyboard) {
26725         reply_markup->is_personal = false;
26726       }
26727       break;
26728     case DialogType::Channel:
26729     case DialogType::Chat:
26730     case DialogType::SecretChat:
26731     case DialogType::None:
26732       // nothing special
26733       break;
26734     default:
26735       UNREACHABLE();
26736   }
26737 
26738   return std::move(reply_markup);
26739 }
26740 
26741 class MessagesManager::ForwardMessagesLogEvent {
26742  public:
26743   DialogId to_dialog_id;
26744   DialogId from_dialog_id;
26745   vector<MessageId> message_ids;
26746   vector<Message *> messages_in;
26747   vector<unique_ptr<Message>> messages_out;
26748 
26749   template <class StorerT>
store(StorerT & storer) const26750   void store(StorerT &storer) const {
26751     td::store(to_dialog_id, storer);
26752     td::store(from_dialog_id, storer);
26753     td::store(message_ids, storer);
26754     td::store(messages_in, storer);
26755   }
26756 
26757   template <class ParserT>
parse(ParserT & parser)26758   void parse(ParserT &parser) {
26759     td::parse(to_dialog_id, parser);
26760     td::parse(from_dialog_id, parser);
26761     td::parse(message_ids, parser);
26762     td::parse(messages_out, parser);
26763   }
26764 };
26765 
save_forward_messages_log_event(DialogId to_dialog_id,DialogId from_dialog_id,const vector<Message * > & messages,const vector<MessageId> & message_ids)26766 uint64 MessagesManager::save_forward_messages_log_event(DialogId to_dialog_id, DialogId from_dialog_id,
26767                                                         const vector<Message *> &messages,
26768                                                         const vector<MessageId> &message_ids) {
26769   ForwardMessagesLogEvent log_event{to_dialog_id, from_dialog_id, message_ids, messages, Auto()};
26770   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::ForwardMessages,
26771                     get_log_event_storer(log_event));
26772 }
26773 
do_forward_messages(DialogId to_dialog_id,DialogId from_dialog_id,const vector<Message * > & messages,const vector<MessageId> & message_ids,uint64 log_event_id)26774 void MessagesManager::do_forward_messages(DialogId to_dialog_id, DialogId from_dialog_id,
26775                                           const vector<Message *> &messages, const vector<MessageId> &message_ids,
26776                                           uint64 log_event_id) {
26777   CHECK(messages.size() == message_ids.size());
26778   if (messages.empty()) {
26779     return;
26780   }
26781 
26782   if (log_event_id == 0 && G()->parameters().use_message_db) {
26783     log_event_id = save_forward_messages_log_event(to_dialog_id, from_dialog_id, messages, message_ids);
26784   }
26785 
26786   auto schedule_date = get_message_schedule_date(messages[0]);
26787 
26788   int32 flags = 0;
26789   if (messages[0]->disable_notification) {
26790     flags |= SEND_MESSAGE_FLAG_DISABLE_NOTIFICATION;
26791   }
26792   if (messages[0]->from_background) {
26793     flags |= SEND_MESSAGE_FLAG_FROM_BACKGROUND;
26794   }
26795   if (messages[0]->in_game_share) {
26796     flags |= SEND_MESSAGE_FLAG_WITH_MY_SCORE;
26797   }
26798   if (schedule_date != 0) {
26799     flags |= SEND_MESSAGE_FLAG_HAS_SCHEDULE_DATE;
26800   }
26801   if (messages[0]->has_explicit_sender) {
26802     flags |= SEND_MESSAGE_FLAG_HAS_SEND_AS;
26803   }
26804 
26805   vector<int64> random_ids =
26806       transform(messages, [this, to_dialog_id](const Message *m) { return begin_send_message(to_dialog_id, m); });
26807   send_closure(td_->create_net_actor<ForwardMessagesActor>(get_erase_log_event_promise(log_event_id)),
26808                &ForwardMessagesActor::send, flags, to_dialog_id, from_dialog_id,
26809                get_send_message_as_input_peer(messages[0]), message_ids, std::move(random_ids), schedule_date,
26810                get_sequence_dispatcher_id(to_dialog_id, MessageContentType::None));
26811 }
26812 
forward_message(DialogId to_dialog_id,DialogId from_dialog_id,MessageId message_id,tl_object_ptr<td_api::messageSendOptions> && options,bool in_game_share,MessageCopyOptions && copy_options)26813 Result<td_api::object_ptr<td_api::message>> MessagesManager::forward_message(
26814     DialogId to_dialog_id, DialogId from_dialog_id, MessageId message_id,
26815     tl_object_ptr<td_api::messageSendOptions> &&options, bool in_game_share, MessageCopyOptions &&copy_options) {
26816   bool need_copy = copy_options.send_copy;
26817   vector<MessageCopyOptions> all_copy_options;
26818   all_copy_options.push_back(std::move(copy_options));
26819   TRY_RESULT(result, forward_messages(to_dialog_id, from_dialog_id, {message_id}, std::move(options), in_game_share,
26820                                       std::move(all_copy_options), false));
26821   CHECK(result->messages_.size() == 1);
26822   if (result->messages_[0] == nullptr) {
26823     return Status::Error(400,
26824                          need_copy ? Slice("The message can't be copied") : Slice("The message can't be forwarded"));
26825   }
26826   return std::move(result->messages_[0]);
26827 }
26828 
create_message_forward_info(DialogId from_dialog_id,DialogId to_dialog_id,const Message * forwarded_message) const26829 unique_ptr<MessagesManager::MessageForwardInfo> MessagesManager::create_message_forward_info(
26830     DialogId from_dialog_id, DialogId to_dialog_id, const Message *forwarded_message) const {
26831   auto content_type = forwarded_message->content->get_type();
26832   if (content_type == MessageContentType::Game || content_type == MessageContentType::Audio) {
26833     return nullptr;
26834   }
26835 
26836   auto my_id = td_->contacts_manager_->get_my_id();
26837   auto message_id = forwarded_message->message_id;
26838 
26839   DialogId saved_from_dialog_id;
26840   MessageId saved_from_message_id;
26841   if (to_dialog_id == DialogId(my_id)) {
26842     saved_from_dialog_id = from_dialog_id;
26843     saved_from_message_id = message_id;
26844   }
26845 
26846   if (forwarded_message->forward_info != nullptr) {
26847     auto forward_info = make_unique<MessageForwardInfo>(*forwarded_message->forward_info);
26848     forward_info->from_dialog_id = saved_from_dialog_id;
26849     forward_info->from_message_id = saved_from_message_id;
26850     return forward_info;
26851   }
26852 
26853   if (from_dialog_id != DialogId(my_id) || content_type == MessageContentType::Dice) {
26854     if (forwarded_message->is_channel_post) {
26855       if (is_broadcast_channel(from_dialog_id)) {
26856         auto author_signature = forwarded_message->sender_user_id.is_valid()
26857                                     ? td_->contacts_manager_->get_user_title(forwarded_message->sender_user_id)
26858                                     : forwarded_message->author_signature;
26859         return td::make_unique<MessageForwardInfo>(UserId(), forwarded_message->date, from_dialog_id,
26860                                                    forwarded_message->message_id, std::move(author_signature), "",
26861                                                    saved_from_dialog_id, saved_from_message_id, "", false);
26862       } else {
26863         LOG(ERROR) << "Don't know how to forward a channel post not from a channel";
26864       }
26865     } else if (forwarded_message->sender_user_id.is_valid() || forwarded_message->sender_dialog_id.is_valid()) {
26866       return td::make_unique<MessageForwardInfo>(
26867           forwarded_message->sender_user_id, forwarded_message->date, forwarded_message->sender_dialog_id, MessageId(),
26868           "", forwarded_message->author_signature, saved_from_dialog_id, saved_from_message_id, "", false);
26869     } else {
26870       LOG(ERROR) << "Don't know how to forward a non-channel post message without forward info and sender";
26871     }
26872   }
26873   return nullptr;
26874 }
26875 
fix_forwarded_message(Message * m,DialogId to_dialog_id,const Message * forwarded_message,int64 media_album_id) const26876 void MessagesManager::fix_forwarded_message(Message *m, DialogId to_dialog_id, const Message *forwarded_message,
26877                                             int64 media_album_id) const {
26878   m->via_bot_user_id = forwarded_message->via_bot_user_id;
26879   m->media_album_id = media_album_id;
26880   if (forwarded_message->view_count > 0 && m->forward_info != nullptr && m->view_count == 0 &&
26881       !(m->message_id.is_scheduled() && is_broadcast_channel(to_dialog_id))) {
26882     m->view_count = forwarded_message->view_count;
26883     m->forward_count = forwarded_message->forward_count;
26884     m->interaction_info_update_date = G()->unix_time();
26885   }
26886 
26887   if (m->content->get_type() == MessageContentType::Game) {
26888     // via_bot_user_id in games is present unless the message is sent by the bot
26889     if (m->via_bot_user_id == UserId()) {
26890       // if there is no via_bot_user_id, then the original message was sent by the game owner
26891       m->via_bot_user_id = forwarded_message->sender_user_id;
26892     }
26893     if (m->via_bot_user_id == td_->contacts_manager_->get_my_id()) {
26894       // if via_bot_user_id is the current bot user, then there should be
26895       m->via_bot_user_id = UserId();
26896     }
26897   }
26898   if (forwarded_message->reply_markup != nullptr &&
26899       forwarded_message->reply_markup->type == ReplyMarkup::Type::InlineKeyboard &&
26900       to_dialog_id.get_type() != DialogType::SecretChat) {
26901     bool need_reply_markup = true;
26902     for (auto &row : forwarded_message->reply_markup->inline_keyboard) {
26903       for (auto &button : row) {
26904         if (button.type == InlineKeyboardButton::Type::Url || button.type == InlineKeyboardButton::Type::UrlAuth) {
26905           // ok
26906           continue;
26907         }
26908         if (m->via_bot_user_id.is_valid() && (button.type == InlineKeyboardButton::Type::SwitchInline ||
26909                                               button.type == InlineKeyboardButton::Type::SwitchInlineCurrentDialog)) {
26910           // ok
26911           continue;
26912         }
26913 
26914         need_reply_markup = false;
26915       }
26916     }
26917     if (need_reply_markup) {
26918       m->reply_markup = make_unique<ReplyMarkup>(*forwarded_message->reply_markup);
26919       for (auto &row : m->reply_markup->inline_keyboard) {
26920         for (auto &button : row) {
26921           if (button.type == InlineKeyboardButton::Type::SwitchInlineCurrentDialog) {
26922             button.type = InlineKeyboardButton::Type::SwitchInline;
26923           }
26924           if (!button.forward_text.empty()) {
26925             button.text = std::move(button.forward_text);
26926             button.forward_text.clear();
26927           }
26928         }
26929       }
26930     }
26931   }
26932 }
26933 
get_forwarded_messages(DialogId to_dialog_id,DialogId from_dialog_id,const vector<MessageId> & message_ids,tl_object_ptr<td_api::messageSendOptions> && options,bool in_game_share,vector<MessageCopyOptions> && copy_options)26934 Result<MessagesManager::ForwardedMessages> MessagesManager::get_forwarded_messages(
26935     DialogId to_dialog_id, DialogId from_dialog_id, const vector<MessageId> &message_ids,
26936     tl_object_ptr<td_api::messageSendOptions> &&options, bool in_game_share,
26937     vector<MessageCopyOptions> &&copy_options) {
26938   CHECK(copy_options.size() == message_ids.size());
26939   if (message_ids.size() > 100) {  // TODO replace with const from config or implement mass-forward
26940     return Status::Error(400, "Too much messages to forward");
26941   }
26942   if (message_ids.empty()) {
26943     return Status::Error(400, "There are no messages to forward");
26944   }
26945 
26946   Dialog *from_dialog = get_dialog_force(from_dialog_id, "forward_messages from");
26947   if (from_dialog == nullptr) {
26948     return Status::Error(400, "Chat to forward messages from not found");
26949   }
26950   if (!have_input_peer(from_dialog_id, AccessRights::Read)) {
26951     return Status::Error(400, "Can't access the chat to forward messages from");
26952   }
26953   if (from_dialog_id.get_type() == DialogType::SecretChat) {
26954     return Status::Error(400, "Can't forward messages from secret chats");
26955   }
26956   if (get_dialog_has_protected_content(from_dialog_id)) {
26957     for (const auto &copy_option : copy_options) {
26958       if (!copy_option.send_copy || !td_->auth_manager_->is_bot()) {
26959         return Status::Error(400, "Administrators of the chat restricted message forwarding");
26960       }
26961     }
26962   }
26963 
26964   Dialog *to_dialog = get_dialog_force(to_dialog_id, "forward_messages to");
26965   if (to_dialog == nullptr) {
26966     return Status::Error(400, "Chat to forward messages to not found");
26967   }
26968 
26969   TRY_STATUS(can_send_message(to_dialog_id));
26970   TRY_RESULT(message_send_options, process_message_send_options(to_dialog_id, std::move(options)));
26971 
26972   {
26973     MessageId last_message_id;
26974     for (auto message_id : message_ids) {
26975       if (message_id.is_valid_scheduled()) {
26976         return Status::Error(400, "Can't forward scheduled messages");
26977       }
26978       if (message_id.is_scheduled() || !message_id.is_valid()) {
26979         return Status::Error(400, "Invalid message identifier");
26980       }
26981 
26982       if (message_id <= last_message_id) {
26983         return Status::Error(400, "Message identifiers must be in a strictly increasing order");
26984       }
26985       last_message_id = message_id;
26986     }
26987   }
26988 
26989   bool to_secret = to_dialog_id.get_type() == DialogType::SecretChat;
26990 
26991   ForwardedMessages result;
26992   result.to_dialog = to_dialog;
26993   result.from_dialog = from_dialog;
26994   result.message_send_options = message_send_options;
26995   auto &copied_messages = result.copied_messages;
26996   auto &forwarded_message_contents = result.forwarded_message_contents;
26997 
26998   std::unordered_map<int64, std::pair<int64, int32>> new_copied_media_album_ids;
26999   std::unordered_map<int64, std::pair<int64, int32>> new_forwarded_media_album_ids;
27000 
27001   for (size_t i = 0; i < message_ids.size(); i++) {
27002     MessageId message_id = get_persistent_message_id(from_dialog, message_ids[i]);
27003 
27004     const Message *forwarded_message = get_message_force(from_dialog, message_id, "get_forwarded_messages");
27005     if (forwarded_message == nullptr) {
27006       LOG(INFO) << "Can't find " << message_id << " to forward";
27007       continue;
27008     }
27009     CHECK(message_id.is_valid());
27010     CHECK(message_id == forwarded_message->message_id);
27011 
27012     if (!can_forward_message(from_dialog_id, forwarded_message)) {
27013       LOG(INFO) << "Can't forward " << message_id;
27014       continue;
27015     }
27016 
27017     bool need_copy = !message_id.is_server() || to_secret || copy_options[i].send_copy;
27018     if (!(need_copy && td_->auth_manager_->is_bot()) && !can_save_message(from_dialog_id, forwarded_message)) {
27019       LOG(INFO) << "Forward of " << message_id << " is restricted";
27020       continue;
27021     }
27022 
27023     auto type = need_copy ? MessageContentDupType::Copy : MessageContentDupType::Forward;
27024     auto top_thread_message_id = copy_options[i].top_thread_message_id;
27025     auto reply_to_message_id = copy_options[i].reply_to_message_id;
27026     auto reply_markup = std::move(copy_options[i].reply_markup);
27027     unique_ptr<MessageContent> content =
27028         dup_message_content(td_, to_dialog_id, forwarded_message->content.get(), type, std::move(copy_options[i]));
27029     if (content == nullptr) {
27030       LOG(INFO) << "Can't forward " << message_id;
27031       continue;
27032     }
27033 
27034     reply_to_message_id = get_reply_to_message_id(to_dialog, top_thread_message_id, reply_to_message_id, false);
27035 
27036     auto can_send_status = can_send_message_content(to_dialog_id, content.get(), !need_copy, td_);
27037     if (can_send_status.is_error()) {
27038       LOG(INFO) << "Can't forward " << message_id << ": " << can_send_status.message();
27039       continue;
27040     }
27041 
27042     auto can_use_options_status = can_use_message_send_options(message_send_options, content, 0);
27043     if (can_use_options_status.is_error()) {
27044       LOG(INFO) << "Can't forward " << message_id << ": " << can_send_status.message();
27045       continue;
27046     }
27047 
27048     if (can_use_top_thread_message_id(to_dialog, top_thread_message_id, reply_to_message_id).is_error()) {
27049       LOG(INFO) << "Ignore invalid message thread ID " << top_thread_message_id;
27050       top_thread_message_id = MessageId();
27051     }
27052 
27053     if (forwarded_message->media_album_id != 0) {
27054       auto &new_media_album_id = need_copy ? new_copied_media_album_ids[forwarded_message->media_album_id]
27055                                            : new_forwarded_media_album_ids[forwarded_message->media_album_id];
27056       new_media_album_id.second++;
27057       if (new_media_album_id.second == 2) {  // have at least 2 messages in the new album
27058         CHECK(new_media_album_id.first == 0);
27059         new_media_album_id.first = generate_new_media_album_id();
27060       }
27061       if (new_media_album_id.second == MAX_GROUPED_MESSAGES + 1) {
27062         CHECK(new_media_album_id.first != 0);
27063         new_media_album_id.first = 0;  // just in case
27064       }
27065     }
27066 
27067     if (need_copy) {
27068       copied_messages.push_back({std::move(content), top_thread_message_id, reply_to_message_id,
27069                                  std::move(reply_markup), forwarded_message->media_album_id,
27070                                  get_message_disable_web_page_preview(forwarded_message), i});
27071     } else {
27072       forwarded_message_contents.push_back({std::move(content), forwarded_message->media_album_id, i});
27073     }
27074   }
27075 
27076   if (2 <= forwarded_message_contents.size() && forwarded_message_contents.size() <= MAX_GROUPED_MESSAGES) {
27077     std::unordered_set<MessageContentType, MessageContentTypeHash> message_content_types;
27078     std::unordered_set<DialogId, DialogIdHash> sender_dialog_ids;
27079     for (auto &message_content : forwarded_message_contents) {
27080       message_content_types.insert(message_content.content->get_type());
27081 
27082       MessageId message_id = get_persistent_message_id(from_dialog, message_ids[message_content.index]);
27083       sender_dialog_ids.insert(get_message_original_sender(get_message(from_dialog, message_id)));
27084     }
27085     if (message_content_types.size() == 1 && is_homogenous_media_group_content(*message_content_types.begin()) &&
27086         sender_dialog_ids.size() == 1 && *sender_dialog_ids.begin() != DialogId()) {
27087       new_forwarded_media_album_ids[0].first = generate_new_media_album_id();
27088       for (auto &message : forwarded_message_contents) {
27089         message.media_album_id = 0;
27090       }
27091     }
27092   }
27093   for (auto &message : forwarded_message_contents) {
27094     message.media_album_id = new_forwarded_media_album_ids[message.media_album_id].first;
27095   }
27096 
27097   if (2 <= copied_messages.size() && copied_messages.size() <= MAX_GROUPED_MESSAGES) {
27098     std::unordered_set<MessageContentType, MessageContentTypeHash> message_content_types;
27099     for (auto &copied_message : copied_messages) {
27100       message_content_types.insert(copied_message.content->get_type());
27101     }
27102     if (message_content_types.size() == 1 && is_homogenous_media_group_content(*message_content_types.begin())) {
27103       new_copied_media_album_ids[0].first = generate_new_media_album_id();
27104       for (auto &message : copied_messages) {
27105         message.media_album_id = 0;
27106       }
27107     }
27108   }
27109   for (auto &message : copied_messages) {
27110     message.media_album_id = new_copied_media_album_ids[message.media_album_id].first;
27111   }
27112   return std::move(result);
27113 }
27114 
forward_messages(DialogId to_dialog_id,DialogId from_dialog_id,vector<MessageId> message_ids,tl_object_ptr<td_api::messageSendOptions> && options,bool in_game_share,vector<MessageCopyOptions> && copy_options,bool only_preview)27115 Result<td_api::object_ptr<td_api::messages>> MessagesManager::forward_messages(
27116     DialogId to_dialog_id, DialogId from_dialog_id, vector<MessageId> message_ids,
27117     tl_object_ptr<td_api::messageSendOptions> &&options, bool in_game_share, vector<MessageCopyOptions> &&copy_options,
27118     bool only_preview) {
27119   TRY_RESULT(forwarded_messages_info,
27120              get_forwarded_messages(to_dialog_id, from_dialog_id, message_ids, std::move(options), in_game_share,
27121                                     std::move(copy_options)));
27122   auto from_dialog = forwarded_messages_info.from_dialog;
27123   auto to_dialog = forwarded_messages_info.to_dialog;
27124   auto message_send_options = forwarded_messages_info.message_send_options;
27125   auto &copied_messages = forwarded_messages_info.copied_messages;
27126   auto &forwarded_message_contents = forwarded_messages_info.forwarded_message_contents;
27127 
27128   vector<td_api::object_ptr<td_api::message>> result(message_ids.size());
27129   vector<Message *> forwarded_messages;
27130   vector<MessageId> forwarded_message_ids;
27131   bool need_update_dialog_pos = false;
27132   for (size_t j = 0; j < forwarded_message_contents.size(); j++) {
27133     MessageId message_id = get_persistent_message_id(from_dialog, message_ids[forwarded_message_contents[j].index]);
27134     const Message *forwarded_message = get_message(from_dialog, message_id);
27135     CHECK(forwarded_message != nullptr);
27136 
27137     auto content = std::move(forwarded_message_contents[j].content);
27138     auto forward_info = create_message_forward_info(from_dialog_id, to_dialog_id, forwarded_message);
27139     if (forward_info != nullptr && !forward_info->is_imported && !is_forward_info_sender_hidden(forward_info.get()) &&
27140         !forward_info->message_id.is_valid() && !forward_info->sender_dialog_id.is_valid() &&
27141         forward_info->sender_user_id.is_valid()) {
27142       auto private_forward_name = td_->contacts_manager_->get_user_private_forward_name(forward_info->sender_user_id);
27143       if (!private_forward_name.empty()) {
27144         forward_info->sender_user_id = UserId();
27145         forward_info->sender_name = std::move(private_forward_name);
27146       }
27147     }
27148 
27149     unique_ptr<Message> message;
27150     Message *m;
27151     if (only_preview) {
27152       message = create_message_to_send(to_dialog, MessageId(), MessageId(), message_send_options, std::move(content),
27153                                        j + 1 != forwarded_message_contents.size(), std::move(forward_info), false,
27154                                        DialogId());
27155       MessageId new_message_id =
27156           message_send_options.schedule_date != 0
27157               ? get_next_yet_unsent_scheduled_message_id(to_dialog, message_send_options.schedule_date)
27158               : get_next_yet_unsent_message_id(to_dialog);
27159       set_message_id(message, new_message_id);
27160       m = message.get();
27161     } else {
27162       m = get_message_to_send(to_dialog, MessageId(), MessageId(), message_send_options, std::move(content),
27163                               &need_update_dialog_pos, j + 1 != forwarded_message_contents.size(),
27164                               std::move(forward_info));
27165     }
27166     fix_forwarded_message(m, to_dialog_id, forwarded_message, forwarded_message_contents[j].media_album_id);
27167     m->in_game_share = in_game_share;
27168     m->real_forward_from_dialog_id = from_dialog_id;
27169     m->real_forward_from_message_id = message_id;
27170 
27171     if (!only_preview) {
27172       send_update_new_message(to_dialog, m);
27173       forwarded_messages.push_back(m);
27174       forwarded_message_ids.push_back(message_id);
27175     }
27176 
27177     result[forwarded_message_contents[j].index] = get_message_object(to_dialog_id, m, "forward_messages");
27178   }
27179 
27180   if (!forwarded_messages.empty()) {
27181     CHECK(!only_preview);
27182     do_forward_messages(to_dialog_id, from_dialog_id, forwarded_messages, forwarded_message_ids, 0);
27183   }
27184 
27185   for (auto &copied_message : copied_messages) {
27186     unique_ptr<Message> message;
27187     Message *m;
27188     if (only_preview) {
27189       message = create_message_to_send(to_dialog, copied_message.top_thread_message_id,
27190                                        copied_message.reply_to_message_id, message_send_options,
27191                                        std::move(copied_message.content), false, nullptr, true, DialogId());
27192       MessageId new_message_id =
27193           message_send_options.schedule_date != 0
27194               ? get_next_yet_unsent_scheduled_message_id(to_dialog, message_send_options.schedule_date)
27195               : get_next_yet_unsent_message_id(to_dialog);
27196       set_message_id(message, new_message_id);
27197       m = message.get();
27198     } else {
27199       m = get_message_to_send(to_dialog, copied_message.top_thread_message_id, copied_message.reply_to_message_id,
27200                               message_send_options, std::move(copied_message.content), &need_update_dialog_pos, false,
27201                               nullptr, true);
27202     }
27203     m->disable_web_page_preview = copied_message.disable_web_page_preview;
27204     m->media_album_id = copied_message.media_album_id;
27205     m->reply_markup = std::move(copied_message.reply_markup);
27206 
27207     if (!only_preview) {
27208       save_send_message_log_event(to_dialog_id, m);
27209       do_send_message(to_dialog_id, m);
27210       send_update_new_message(to_dialog, m);
27211     }
27212 
27213     result[copied_message.index] = get_message_object(to_dialog_id, m, "forward_messages");
27214   }
27215 
27216   if (need_update_dialog_pos) {
27217     CHECK(!only_preview);
27218     send_update_chat_last_message(to_dialog, "forward_messages");
27219   }
27220 
27221   return get_messages_object(-1, std::move(result), false);
27222 }
27223 
resend_messages(DialogId dialog_id,vector<MessageId> message_ids)27224 Result<vector<MessageId>> MessagesManager::resend_messages(DialogId dialog_id, vector<MessageId> message_ids) {
27225   if (message_ids.empty()) {
27226     return Status::Error(400, "There are no messages to resend");
27227   }
27228 
27229   Dialog *d = get_dialog_force(dialog_id, "resend_messages");
27230   if (d == nullptr) {
27231     return Status::Error(400, "Chat not found");
27232   }
27233 
27234   TRY_STATUS(can_send_message(dialog_id));
27235 
27236   MessageId last_message_id;
27237   for (auto &message_id : message_ids) {
27238     message_id = get_persistent_message_id(d, message_id);
27239     const Message *m = get_message_force(d, message_id, "resend_messages");
27240     if (m == nullptr) {
27241       return Status::Error(400, "Message not found");
27242     }
27243     if (!m->is_failed_to_send) {
27244       return Status::Error(400, "Message is not failed to send");
27245     }
27246     if (!can_resend_message(m)) {
27247       return Status::Error(400, "Message can't be re-sent");
27248     }
27249     if (m->try_resend_at > Time::now()) {
27250       return Status::Error(400, "Message can't be re-sent yet");
27251     }
27252     if (last_message_id != MessageId()) {
27253       if (m->message_id.is_scheduled() != last_message_id.is_scheduled()) {
27254         return Status::Error(400, "Messages must be all scheduled or ordinary");
27255       }
27256       if (m->message_id <= last_message_id) {
27257         return Status::Error(400, "Message identifiers must be in a strictly increasing order");
27258       }
27259     }
27260     last_message_id = m->message_id;
27261   }
27262 
27263   vector<unique_ptr<MessageContent>> new_contents(message_ids.size());
27264   std::unordered_map<int64, std::pair<int64, int32>> new_media_album_ids;
27265   for (size_t i = 0; i < message_ids.size(); i++) {
27266     MessageId message_id = message_ids[i];
27267     const Message *m = get_message(d, message_id);
27268     CHECK(m != nullptr);
27269 
27270     unique_ptr<MessageContent> content =
27271         dup_message_content(td_, dialog_id, m->content.get(), MessageContentDupType::Send, MessageCopyOptions());
27272     if (content == nullptr) {
27273       LOG(INFO) << "Can't resend " << m->message_id;
27274       continue;
27275     }
27276 
27277     auto can_send_status = can_send_message_content(dialog_id, content.get(), false, td_);
27278     if (can_send_status.is_error()) {
27279       LOG(INFO) << "Can't resend " << m->message_id << ": " << can_send_status.message();
27280       continue;
27281     }
27282 
27283     new_contents[i] = std::move(content);
27284 
27285     if (m->media_album_id != 0) {
27286       auto &new_media_album_id = new_media_album_ids[m->media_album_id];
27287       new_media_album_id.second++;
27288       if (new_media_album_id.second == 2) {  // have at least 2 messages in the new album
27289         CHECK(new_media_album_id.first == 0);
27290         new_media_album_id.first = generate_new_media_album_id();
27291       }
27292       if (new_media_album_id.second == MAX_GROUPED_MESSAGES + 1) {
27293         CHECK(new_media_album_id.first != 0);
27294         new_media_album_id.first = 0;  // just in case
27295       }
27296     }
27297   }
27298 
27299   vector<MessageId> result(message_ids.size());
27300   bool need_update_dialog_pos = false;
27301   for (size_t i = 0; i < message_ids.size(); i++) {
27302     if (new_contents[i] == nullptr) {
27303       continue;
27304     }
27305 
27306     being_readded_message_id_ = {dialog_id, message_ids[i]};
27307     unique_ptr<Message> message = delete_message(d, message_ids[i], true, &need_update_dialog_pos, "resend_messages");
27308     CHECK(message != nullptr);
27309     send_update_delete_messages(dialog_id, {message->message_id.get()}, true, false);
27310 
27311     auto need_another_sender =
27312         message->send_error_code == 400 && message->send_error_message == CSlice("SEND_AS_PEER_INVALID");
27313     MessageSendOptions options(message->disable_notification, message->from_background,
27314                                get_message_schedule_date(message.get()));
27315     Message *m = get_message_to_send(
27316         d, message->top_thread_message_id,
27317         get_reply_to_message_id(d, message->top_thread_message_id, message->reply_to_message_id, false), options,
27318         std::move(new_contents[i]), &need_update_dialog_pos, false, nullptr, message->is_copy,
27319         need_another_sender ? DialogId() : get_message_sender(message.get()));
27320     m->reply_markup = std::move(message->reply_markup);
27321     m->via_bot_user_id = message->via_bot_user_id;
27322     m->disable_web_page_preview = message->disable_web_page_preview;
27323     m->clear_draft = false;  // never clear draft in resend
27324     m->ttl = message->ttl;
27325     m->is_content_secret = message->is_content_secret;
27326     m->media_album_id = new_media_album_ids[message->media_album_id].first;
27327     m->send_emoji = message->send_emoji;
27328     m->has_explicit_sender |= message->has_explicit_sender;
27329 
27330     save_send_message_log_event(dialog_id, m);
27331     do_send_message(dialog_id, m);
27332 
27333     send_update_new_message(d, m);
27334 
27335     result[i] = m->message_id;
27336     being_readded_message_id_ = FullMessageId();
27337   }
27338 
27339   if (need_update_dialog_pos) {
27340     send_update_chat_last_message(d, "resend_messages");
27341   }
27342 
27343   return result;
27344 }
27345 
send_screenshot_taken_notification_message(DialogId dialog_id)27346 Status MessagesManager::send_screenshot_taken_notification_message(DialogId dialog_id) {
27347   auto dialog_type = dialog_id.get_type();
27348   if (dialog_type != DialogType::User && dialog_type != DialogType::SecretChat) {
27349     return Status::Error(400, "Notification about taken screenshot can be sent only in private and secret chats");
27350   }
27351 
27352   LOG(INFO) << "Begin to send notification about taken screenshot in " << dialog_id;
27353 
27354   Dialog *d = get_dialog_force(dialog_id, "send_screenshot_taken_notification_message");
27355   if (d == nullptr) {
27356     return Status::Error(400, "Chat not found");
27357   }
27358 
27359   TRY_STATUS(can_send_message(dialog_id));
27360 
27361   if (dialog_type == DialogType::User) {
27362     bool need_update_dialog_pos = false;
27363     const Message *m = get_message_to_send(d, MessageId(), MessageId(), MessageSendOptions(),
27364                                            create_screenshot_taken_message_content(), &need_update_dialog_pos);
27365 
27366     do_send_screenshot_taken_notification_message(dialog_id, m, 0);
27367 
27368     send_update_new_message(d, m);
27369     if (need_update_dialog_pos) {
27370       send_update_chat_last_message(d, "send_screenshot_taken_notification_message");
27371     }
27372   } else {
27373     send_closure(td_->secret_chats_manager_, &SecretChatsManager::notify_screenshot_taken,
27374                  dialog_id.get_secret_chat_id(),
27375                  Promise<>());  // TODO Promise
27376   }
27377 
27378   return Status::OK();
27379 }
27380 
27381 class MessagesManager::SendScreenshotTakenNotificationMessageLogEvent {
27382  public:
27383   DialogId dialog_id;
27384   const Message *m_in = nullptr;
27385   unique_ptr<Message> m_out;
27386 
27387   template <class StorerT>
store(StorerT & storer) const27388   void store(StorerT &storer) const {
27389     td::store(dialog_id, storer);
27390     td::store(*m_in, storer);
27391   }
27392 
27393   template <class ParserT>
parse(ParserT & parser)27394   void parse(ParserT &parser) {
27395     td::parse(dialog_id, parser);
27396     td::parse(m_out, parser);
27397   }
27398 };
27399 
save_send_screenshot_taken_notification_message_log_event(DialogId dialog_id,const Message * m)27400 uint64 MessagesManager::save_send_screenshot_taken_notification_message_log_event(DialogId dialog_id,
27401                                                                                   const Message *m) {
27402   if (!G()->parameters().use_message_db) {
27403     return 0;
27404   }
27405 
27406   CHECK(m != nullptr);
27407   LOG(INFO) << "Save " << FullMessageId(dialog_id, m->message_id) << " to binlog";
27408   SendScreenshotTakenNotificationMessageLogEvent log_event;
27409   log_event.dialog_id = dialog_id;
27410   log_event.m_in = m;
27411   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::SendScreenshotTakenNotificationMessage,
27412                     get_log_event_storer(log_event));
27413 }
27414 
do_send_screenshot_taken_notification_message(DialogId dialog_id,const Message * m,uint64 log_event_id)27415 void MessagesManager::do_send_screenshot_taken_notification_message(DialogId dialog_id, const Message *m,
27416                                                                     uint64 log_event_id) {
27417   LOG(INFO) << "Do send screenshot taken notification " << FullMessageId(dialog_id, m->message_id);
27418   CHECK(dialog_id.get_type() == DialogType::User);
27419 
27420   if (log_event_id == 0) {
27421     log_event_id = save_send_screenshot_taken_notification_message_log_event(dialog_id, m);
27422   }
27423 
27424   int64 random_id = begin_send_message(dialog_id, m);
27425   td_->create_handler<SendScreenshotNotificationQuery>(get_erase_log_event_promise(log_event_id))
27426       ->send(dialog_id, random_id);
27427 }
27428 
add_local_message(DialogId dialog_id,td_api::object_ptr<td_api::MessageSender> && sender,MessageId reply_to_message_id,bool disable_notification,tl_object_ptr<td_api::InputMessageContent> && input_message_content)27429 Result<MessageId> MessagesManager::add_local_message(
27430     DialogId dialog_id, td_api::object_ptr<td_api::MessageSender> &&sender, MessageId reply_to_message_id,
27431     bool disable_notification, tl_object_ptr<td_api::InputMessageContent> &&input_message_content) {
27432   if (input_message_content == nullptr) {
27433     return Status::Error(400, "Can't add local message without content");
27434   }
27435 
27436   LOG(INFO) << "Begin to add local message to " << dialog_id << " in reply to " << reply_to_message_id;
27437   Dialog *d = get_dialog_force(dialog_id, "add_local_message");
27438   if (d == nullptr) {
27439     return Status::Error(400, "Chat not found");
27440   }
27441 
27442   if (!have_input_peer(dialog_id, AccessRights::Read)) {
27443     return Status::Error(400, "Can't access the chat");
27444   }
27445   TRY_RESULT(message_content, process_input_message_content(dialog_id, std::move(input_message_content)));
27446   if (message_content.content->get_type() == MessageContentType::Poll) {
27447     return Status::Error(400, "Can't add local poll message");
27448   }
27449   if (message_content.content->get_type() == MessageContentType::Game) {
27450     return Status::Error(400, "Can't add local game message");
27451   }
27452   if (message_content.content->get_type() == MessageContentType::Dice) {
27453     return Status::Error(400, "Can't add local dice message");
27454   }
27455 
27456   bool is_channel_post = is_broadcast_channel(dialog_id);
27457   UserId sender_user_id;
27458   DialogId sender_dialog_id;
27459   if (sender != nullptr) {
27460     TRY_RESULT_ASSIGN(sender_dialog_id, get_message_sender_dialog_id(td_, sender, true, false));
27461     auto sender_dialog_type = sender_dialog_id.get_type();
27462     if (sender_dialog_type == DialogType::User) {
27463       sender_user_id = sender_dialog_id.get_user_id();
27464       sender_dialog_id = DialogId();
27465     } else if (sender_dialog_type != DialogType::Channel) {
27466       return Status::Error(400, "Sender chat must be a supergroup or channel");
27467     }
27468   } else if (is_channel_post) {
27469     sender_dialog_id = dialog_id;
27470   } else {
27471     return Status::Error(400, "The message must have a sender");
27472   }
27473   if (is_channel_post && sender_user_id.is_valid()) {
27474     return Status::Error(400, "Channel post can't have a sender user");
27475   }
27476   if (is_channel_post && sender_dialog_id != dialog_id) {
27477     return Status::Error(400, "Channel post must have the channel as a sender");
27478   }
27479 
27480   auto dialog_type = dialog_id.get_type();
27481   auto my_id = td_->contacts_manager_->get_my_id();
27482   if (sender_user_id != my_id) {
27483     if (dialog_type == DialogType::User && DialogId(sender_user_id) != dialog_id) {
27484       return Status::Error(400, "Wrong sender user");
27485     }
27486     if (dialog_type == DialogType::SecretChat) {
27487       auto peer_user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id());
27488       if (!peer_user_id.is_valid() || sender_user_id != peer_user_id) {
27489         return Status::Error(400, "Wrong sender user");
27490       }
27491     }
27492   }
27493 
27494   MessageId message_id = get_next_local_message_id(d);
27495 
27496   auto m = make_unique<Message>();
27497   set_message_id(m, message_id);
27498   if (is_channel_post) {
27499     // sender of the post can be hidden
27500     if (td_->contacts_manager_->get_channel_sign_messages(dialog_id.get_channel_id())) {
27501       m->author_signature = td_->contacts_manager_->get_user_title(sender_user_id);
27502     }
27503     m->sender_dialog_id = sender_dialog_id;
27504   } else {
27505     m->sender_user_id = sender_user_id;
27506     m->sender_dialog_id = sender_dialog_id;
27507   }
27508   m->date = G()->unix_time();
27509   m->reply_to_message_id = get_reply_to_message_id(d, MessageId(), reply_to_message_id, false);
27510   if (m->reply_to_message_id.is_valid() && !message_id.is_scheduled()) {
27511     const Message *reply_m = get_message(d, m->reply_to_message_id);
27512     if (reply_m != nullptr) {
27513       m->top_thread_message_id = reply_m->top_thread_message_id;
27514     }
27515   }
27516   m->is_channel_post = is_channel_post;
27517   m->is_outgoing = dialog_id != DialogId(my_id) && sender_user_id == my_id;
27518   m->disable_notification = disable_notification;
27519   m->from_background = false;
27520   m->view_count = 0;
27521   m->forward_count = 0;
27522   m->content = std::move(message_content.content);
27523   m->disable_web_page_preview = message_content.disable_web_page_preview;
27524   m->clear_draft = message_content.clear_draft;
27525   if (dialog_type == DialogType::SecretChat) {
27526     m->ttl = td_->contacts_manager_->get_secret_chat_ttl(dialog_id.get_secret_chat_id());
27527     if (is_service_message_content(m->content->get_type())) {
27528       m->ttl = 0;
27529     }
27530   } else if (message_content.ttl > 0) {
27531     m->ttl = message_content.ttl;
27532   }
27533   m->is_content_secret = is_secret_message_content(m->ttl, m->content->get_type());
27534   m->send_emoji = std::move(message_content.emoji);
27535 
27536   m->have_previous = true;
27537   m->have_next = true;
27538 
27539   bool need_update = true;
27540   bool need_update_dialog_pos = false;
27541   auto result =
27542       add_message_to_dialog(d, std::move(m), true, &need_update, &need_update_dialog_pos, "add local message");
27543   LOG_CHECK(result != nullptr) << message_id << " " << debug_add_message_to_dialog_fail_reason_;
27544   register_new_local_message_id(d, result);
27545 
27546   if (is_message_auto_read(dialog_id, result->is_outgoing)) {
27547     if (result->is_outgoing) {
27548       read_history_outbox(dialog_id, message_id);
27549     } else {
27550       read_history_inbox(dialog_id, message_id, 0, "add_local_message");
27551     }
27552   }
27553 
27554   if (message_content.clear_draft) {
27555     update_dialog_draft_message(d, nullptr, false, !need_update_dialog_pos);
27556   }
27557 
27558   send_update_new_message(d, result);
27559   if (need_update_dialog_pos) {
27560     send_update_chat_last_message(d, "add_local_message");
27561   }
27562 
27563   return message_id;
27564 }
27565 
get_message_file_type(const string & message_file_head,Promise<td_api::object_ptr<td_api::MessageFileType>> && promise)27566 void MessagesManager::get_message_file_type(const string &message_file_head,
27567                                             Promise<td_api::object_ptr<td_api::MessageFileType>> &&promise) {
27568   td_->create_handler<CheckHistoryImportQuery>(std::move(promise))->send(message_file_head);
27569 }
27570 
can_import_messages(DialogId dialog_id)27571 Status MessagesManager::can_import_messages(DialogId dialog_id) {
27572   if (!have_dialog_force(dialog_id, "can_import_messages")) {
27573     return Status::Error(400, "Chat not found");
27574   }
27575 
27576   TRY_STATUS(can_send_message(dialog_id));
27577 
27578   switch (dialog_id.get_type()) {
27579     case DialogType::User:
27580       if (!td_->contacts_manager_->is_user_contact(dialog_id.get_user_id(), true)) {
27581         return Status::Error(400, "User must be a mutual contact");
27582       }
27583       break;
27584     case DialogType::Chat:
27585       return Status::Error(400, "Basic groups must be updagraded to supergroups first");
27586     case DialogType::Channel:
27587       if (is_broadcast_channel(dialog_id)) {
27588         return Status::Error(400, "Can't import messages to channels");
27589       }
27590       if (!td_->contacts_manager_->get_channel_status(dialog_id.get_channel_id()).can_change_info_and_settings()) {
27591         return Status::Error(400, "Not enough rights to import messages");
27592       }
27593       break;
27594     case DialogType::SecretChat:
27595       return Status::Error(400, "Can't import messages to secret chats");
27596     case DialogType::None:
27597     default:
27598       UNREACHABLE();
27599   }
27600 
27601   return Status::OK();
27602 }
27603 
get_message_import_confirmation_text(DialogId dialog_id,Promise<string> && promise)27604 void MessagesManager::get_message_import_confirmation_text(DialogId dialog_id, Promise<string> &&promise) {
27605   TRY_STATUS_PROMISE(promise, can_import_messages(dialog_id));
27606 
27607   td_->create_handler<CheckHistoryImportPeerQuery>(std::move(promise))->send(dialog_id);
27608 }
27609 
import_messages(DialogId dialog_id,const td_api::object_ptr<td_api::InputFile> & message_file,const vector<td_api::object_ptr<td_api::InputFile>> & attached_files,Promise<Unit> && promise)27610 void MessagesManager::import_messages(DialogId dialog_id, const td_api::object_ptr<td_api::InputFile> &message_file,
27611                                       const vector<td_api::object_ptr<td_api::InputFile>> &attached_files,
27612                                       Promise<Unit> &&promise) {
27613   TRY_STATUS_PROMISE(promise, can_import_messages(dialog_id));
27614 
27615   auto r_file_id = td_->file_manager_->get_input_file_id(FileType::Document, message_file, dialog_id, false, false);
27616   if (r_file_id.is_error()) {
27617     // TODO TRY_RESULT_PROMISE(promise, ...);
27618     return promise.set_error(Status::Error(400, r_file_id.error().message()));
27619   }
27620   FileId file_id = r_file_id.ok();
27621 
27622   vector<FileId> attached_file_ids;
27623   attached_file_ids.reserve(attached_files.size());
27624   for (auto &attached_file : attached_files) {
27625     auto file_type = td_->file_manager_->guess_file_type(attached_file);
27626     if (file_type != FileType::Animation && file_type != FileType::Audio && file_type != FileType::Document &&
27627         file_type != FileType::Photo && file_type != FileType::Sticker && file_type != FileType::Video &&
27628         file_type != FileType::VoiceNote) {
27629       LOG(INFO) << "Skip attached file of type " << file_type;
27630       continue;
27631     }
27632     auto r_attached_file_id = td_->file_manager_->get_input_file_id(file_type, attached_file, dialog_id, false, false);
27633     if (r_attached_file_id.is_error()) {
27634       // TODO TRY_RESULT_PROMISE(promise, ...);
27635       return promise.set_error(Status::Error(400, r_attached_file_id.error().message()));
27636     }
27637     attached_file_ids.push_back(r_attached_file_id.ok());
27638   }
27639 
27640   upload_imported_messages(dialog_id, td_->file_manager_->dup_file_id(file_id), std::move(attached_file_ids), false,
27641                            std::move(promise));
27642 }
27643 
upload_imported_messages(DialogId dialog_id,FileId file_id,vector<FileId> attached_file_ids,bool is_reupload,Promise<Unit> && promise,vector<int> bad_parts)27644 void MessagesManager::upload_imported_messages(DialogId dialog_id, FileId file_id, vector<FileId> attached_file_ids,
27645                                                bool is_reupload, Promise<Unit> &&promise, vector<int> bad_parts) {
27646   CHECK(file_id.is_valid());
27647   LOG(INFO) << "Ask to upload imported messages file " << file_id;
27648   CHECK(being_uploaded_imported_messages_.find(file_id) == being_uploaded_imported_messages_.end());
27649   being_uploaded_imported_messages_.emplace(
27650       file_id, td::make_unique<UploadedImportedMessagesInfo>(dialog_id, std::move(attached_file_ids), is_reupload,
27651                                                              std::move(promise)));
27652   // TODO use force_reupload if is_reupload
27653   td_->file_manager_->resume_upload(file_id, std::move(bad_parts), upload_imported_messages_callback_, 1, 0, false,
27654                                     true);
27655 }
27656 
start_import_messages(DialogId dialog_id,int64 import_id,vector<FileId> && attached_file_ids,Promise<Unit> && promise)27657 void MessagesManager::start_import_messages(DialogId dialog_id, int64 import_id, vector<FileId> &&attached_file_ids,
27658                                             Promise<Unit> &&promise) {
27659   TRY_STATUS_PROMISE(promise, G()->close_status());
27660   TRY_STATUS_PROMISE(promise, can_send_message(dialog_id));
27661 
27662   auto pending_message_import = make_unique<PendingMessageImport>();
27663   pending_message_import->dialog_id = dialog_id;
27664   pending_message_import->import_id = import_id;
27665   pending_message_import->promise = std::move(promise);
27666 
27667   auto &multipromise = pending_message_import->upload_files_multipromise;
27668 
27669   int64 random_id;
27670   do {
27671     random_id = Random::secure_int64();
27672   } while (random_id == 0 || pending_message_imports_.find(random_id) != pending_message_imports_.end());
27673   pending_message_imports_[random_id] = std::move(pending_message_import);
27674 
27675   multipromise.add_promise(PromiseCreator::lambda([actor_id = actor_id(this), random_id](Result<Unit> result) {
27676     send_closure_later(actor_id, &MessagesManager::on_imported_message_attachments_uploaded, random_id,
27677                        std::move(result));
27678   }));
27679   auto lock_promise = multipromise.get_promise();
27680 
27681   for (auto attached_file_id : attached_file_ids) {
27682     upload_imported_message_attachment(dialog_id, import_id, td_->file_manager_->dup_file_id(attached_file_id), false,
27683                                        multipromise.get_promise());
27684   }
27685 
27686   lock_promise.set_value(Unit());
27687 }
27688 
upload_imported_message_attachment(DialogId dialog_id,int64 import_id,FileId file_id,bool is_reupload,Promise<Unit> && promise,vector<int> bad_parts)27689 void MessagesManager::upload_imported_message_attachment(DialogId dialog_id, int64 import_id, FileId file_id,
27690                                                          bool is_reupload, Promise<Unit> &&promise,
27691                                                          vector<int> bad_parts) {
27692   CHECK(file_id.is_valid());
27693   LOG(INFO) << "Ask to upload improted message attached file " << file_id;
27694   CHECK(being_uploaded_imported_message_attachments_.find(file_id) ==
27695         being_uploaded_imported_message_attachments_.end());
27696   being_uploaded_imported_message_attachments_.emplace(
27697       file_id,
27698       td::make_unique<UploadedImportedMessageAttachmentInfo>(dialog_id, import_id, is_reupload, std::move(promise)));
27699   // TODO use force_reupload if is_reupload
27700   td_->file_manager_->resume_upload(file_id, std::move(bad_parts), upload_imported_message_attachment_callback_, 1, 0,
27701                                     false, true);
27702 }
27703 
on_imported_message_attachments_uploaded(int64 random_id,Result<Unit> && result)27704 void MessagesManager::on_imported_message_attachments_uploaded(int64 random_id, Result<Unit> &&result) {
27705   if (G()->close_flag()) {
27706     result = Global::request_aborted_error();
27707   }
27708 
27709   auto it = pending_message_imports_.find(random_id);
27710   CHECK(it != pending_message_imports_.end());
27711 
27712   auto pending_message_import = std::move(it->second);
27713   CHECK(pending_message_import != nullptr);
27714 
27715   pending_message_imports_.erase(it);
27716 
27717   if (result.is_error()) {
27718     pending_message_import->promise.set_error(result.move_as_error());
27719     return;
27720   }
27721 
27722   CHECK(pending_message_import->upload_files_multipromise.promise_count() == 0);
27723 
27724   auto promise = std::move(pending_message_import->promise);
27725   auto dialog_id = pending_message_import->dialog_id;
27726 
27727   TRY_STATUS_PROMISE(promise, can_send_message(dialog_id));
27728 
27729   td_->create_handler<StartImportHistoryQuery>(std::move(promise))->send(dialog_id, pending_message_import->import_id);
27730 }
27731 
on_update_message_id(int64 random_id,MessageId new_message_id,const string & source)27732 bool MessagesManager::on_update_message_id(int64 random_id, MessageId new_message_id, const string &source) {
27733   if (!new_message_id.is_valid() || !new_message_id.is_server()) {
27734     LOG(ERROR) << "Receive " << new_message_id << " in updateMessageId with random_id " << random_id << " from "
27735                << source;
27736     return false;
27737   }
27738 
27739   auto it = being_sent_messages_.find(random_id);
27740   if (it == being_sent_messages_.end()) {
27741     // update about a new message sent from other device or a service message
27742     LOG(INFO) << "Receive not send outgoing " << new_message_id << " with random_id = " << random_id;
27743     return true;
27744   }
27745 
27746   auto dialog_id = it->second.get_dialog_id();
27747   auto old_message_id = it->second.get_message_id();
27748 
27749   being_sent_messages_.erase(it);
27750 
27751   if (!have_message_force({dialog_id, old_message_id}, "on_update_message_id")) {
27752     delete_sent_message_on_server(dialog_id, new_message_id);
27753     return true;
27754   }
27755 
27756   LOG(INFO) << "Save correspondence from " << new_message_id << " in " << dialog_id << " to " << old_message_id;
27757   CHECK(old_message_id.is_yet_unsent());
27758   update_message_ids_[FullMessageId(dialog_id, new_message_id)] = old_message_id;
27759   return true;
27760 }
27761 
on_update_scheduled_message_id(int64 random_id,ScheduledServerMessageId new_message_id,const string & source)27762 bool MessagesManager::on_update_scheduled_message_id(int64 random_id, ScheduledServerMessageId new_message_id,
27763                                                      const string &source) {
27764   if (!new_message_id.is_valid()) {
27765     LOG(ERROR) << "Receive " << new_message_id << " in updateMessageId with random_id " << random_id << " from "
27766                << source;
27767     return false;
27768   }
27769 
27770   auto it = being_sent_messages_.find(random_id);
27771   if (it == being_sent_messages_.end()) {
27772     LOG(ERROR) << "Receive not send outgoing " << new_message_id << " with random_id = " << random_id;
27773     return false;
27774   }
27775 
27776   auto dialog_id = it->second.get_dialog_id();
27777   auto old_message_id = it->second.get_message_id();
27778 
27779   being_sent_messages_.erase(it);
27780 
27781   if (!have_message_force({dialog_id, old_message_id}, "on_update_scheduled_message_id")) {
27782     delete_sent_message_on_server(dialog_id, MessageId(new_message_id, std::numeric_limits<int32>::max()));
27783     return true;
27784   }
27785 
27786   LOG(INFO) << "Save correspondence from " << new_message_id << " in " << dialog_id << " to " << old_message_id;
27787   CHECK(old_message_id.is_yet_unsent());
27788   update_scheduled_message_ids_[dialog_id][new_message_id] = old_message_id;
27789   return true;
27790 }
27791 
on_get_dialog_error(DialogId dialog_id,const Status & status,const string & source)27792 bool MessagesManager::on_get_dialog_error(DialogId dialog_id, const Status &status, const string &source) {
27793   if (status.message() == CSlice("BOT_METHOD_INVALID")) {
27794     LOG(ERROR) << "Receive BOT_METHOD_INVALID from " << source;
27795     return true;
27796   }
27797   if (G()->is_expected_error(status)) {
27798     return true;
27799   }
27800   if (status.message() == CSlice("SEND_AS_PEER_INVALID")) {
27801     reload_dialog_info_full(dialog_id);
27802     return true;
27803   }
27804 
27805   switch (dialog_id.get_type()) {
27806     case DialogType::User:
27807     case DialogType::Chat:
27808     case DialogType::SecretChat:
27809       // to be implemented if necessary
27810       break;
27811     case DialogType::Channel:
27812       return td_->contacts_manager_->on_get_channel_error(dialog_id.get_channel_id(), status, source);
27813     case DialogType::None:
27814       // to be implemented if necessary
27815       break;
27816     default:
27817       UNREACHABLE();
27818   }
27819   return false;
27820 }
27821 
on_dialog_updated(DialogId dialog_id,const char * source)27822 void MessagesManager::on_dialog_updated(DialogId dialog_id, const char *source) {
27823   if (G()->parameters().use_message_db) {
27824     LOG(INFO) << "Update " << dialog_id << " from " << source;
27825     pending_updated_dialog_timeout_.add_timeout_in(dialog_id.get(), MAX_SAVE_DIALOG_DELAY);
27826   }
27827 }
27828 
send_update_new_message(const Dialog * d,const Message * m)27829 void MessagesManager::send_update_new_message(const Dialog *d, const Message *m) {
27830   CHECK(d != nullptr);
27831   CHECK(m != nullptr);
27832   CHECK(d->is_update_new_chat_sent);
27833   send_closure(
27834       G()->td(), &Td::send_update,
27835       make_tl_object<td_api::updateNewMessage>(get_message_object(d->dialog_id, m, "send_update_new_message")));
27836 }
27837 
get_notification_group_info(Dialog * d,const Message * m)27838 MessagesManager::NotificationGroupInfo &MessagesManager::get_notification_group_info(Dialog *d, const Message *m) {
27839   CHECK(d != nullptr);
27840   CHECK(m != nullptr);
27841   return is_from_mention_notification_group(d, m) ? d->mention_notification_group : d->message_notification_group;
27842 }
27843 
get_dialog_notification_group_id(DialogId dialog_id,NotificationGroupInfo & group_info)27844 NotificationGroupId MessagesManager::get_dialog_notification_group_id(DialogId dialog_id,
27845                                                                       NotificationGroupInfo &group_info) {
27846   if (td_->auth_manager_->is_bot()) {
27847     // just in case
27848     return NotificationGroupId();
27849   }
27850   if (!group_info.group_id.is_valid()) {
27851     NotificationGroupId next_notification_group_id;
27852     do {
27853       next_notification_group_id = td_->notification_manager_->get_next_notification_group_id();
27854       if (!next_notification_group_id.is_valid()) {
27855         return NotificationGroupId();
27856       }
27857     } while (get_message_notification_group_force(next_notification_group_id).dialog_id.is_valid());
27858     group_info.group_id = next_notification_group_id;
27859     group_info.is_changed = true;
27860     VLOG(notifications) << "Assign " << next_notification_group_id << " to " << dialog_id;
27861     on_dialog_updated(dialog_id, "get_dialog_notification_group_id");
27862 
27863     notification_group_id_to_dialog_id_.emplace(next_notification_group_id, dialog_id);
27864 
27865     if (running_get_channel_difference(dialog_id) || get_channel_difference_to_log_event_id_.count(dialog_id) != 0) {
27866       send_closure_later(G()->notification_manager(), &NotificationManager::before_get_chat_difference,
27867                          next_notification_group_id);
27868     }
27869   }
27870 
27871   CHECK(group_info.group_id.is_valid());
27872 
27873   // notification group must be preloaded to guarantee that there is no race between
27874   // get_message_notifications_from_database_force and new notifications added right now
27875   td_->notification_manager_->load_group_force(group_info.group_id);
27876 
27877   return group_info.group_id;
27878 }
27879 
get_message_push_notification_info(DialogId dialog_id,MessageId message_id,int64 random_id,UserId sender_user_id,DialogId sender_dialog_id,int32 date,bool is_from_scheduled,bool contains_mention,bool is_pinned,bool is_from_binlog)27880 Result<MessagesManager::MessagePushNotificationInfo> MessagesManager::get_message_push_notification_info(
27881     DialogId dialog_id, MessageId message_id, int64 random_id, UserId sender_user_id, DialogId sender_dialog_id,
27882     int32 date, bool is_from_scheduled, bool contains_mention, bool is_pinned, bool is_from_binlog) {
27883   if (!is_from_scheduled && dialog_id == get_my_dialog_id()) {
27884     return Status::Error("Ignore notification in chat with self");
27885   }
27886   if (td_->auth_manager_->is_bot()) {
27887     return Status::Error("Ignore notification sent to bot");
27888   }
27889 
27890   Dialog *d = get_dialog_force(dialog_id, "get_message_push_notification_info");
27891   if (d == nullptr) {
27892     return Status::Error(406, "Ignore notification in unknown chat");
27893   }
27894   if (sender_dialog_id.is_valid() && !have_dialog_force(sender_dialog_id, "get_message_push_notification_info")) {
27895     return Status::Error(406, "Ignore notification sent by unknown chat");
27896   }
27897 
27898   if (is_from_scheduled && dialog_id != get_my_dialog_id() &&
27899       G()->shared_config().get_option_boolean("disable_sent_scheduled_message_notifications")) {
27900     return Status::Error("Ignore notification about sent scheduled message");
27901   }
27902 
27903   bool is_new_pinned = is_pinned && message_id.is_valid() && message_id > d->max_notification_message_id;
27904   CHECK(!message_id.is_scheduled());
27905   if (message_id.is_valid()) {
27906     if (message_id <= d->last_new_message_id) {
27907       return Status::Error("Ignore notification about known message");
27908     }
27909     if (!is_from_binlog && message_id == d->max_notification_message_id) {
27910       return Status::Error("Ignore previously added message push notification");
27911     }
27912     if (!is_from_binlog && message_id < d->max_notification_message_id) {
27913       return Status::Error("Ignore out of order message push notification");
27914     }
27915     if (message_id <= d->last_read_inbox_message_id) {
27916       return Status::Error("Ignore notification about read message");
27917     }
27918     if (message_id <= d->last_clear_history_message_id) {
27919       return Status::Error("Ignore notification about message from cleared chat history");
27920     }
27921     if (d->deleted_message_ids.count(message_id)) {
27922       return Status::Error("Ignore notification about deleted message");
27923     }
27924     if (message_id <= d->max_unavailable_message_id) {
27925       return Status::Error("Ignore notification about unavailable message");
27926     }
27927   }
27928   if (random_id != 0) {
27929     CHECK(dialog_id.get_type() == DialogType::SecretChat);
27930     if (get_message_id_by_random_id(d, random_id, "get_message_push_notification_info").is_valid()) {
27931       return Status::Error(406, "Ignore notification about known secret message");
27932     }
27933   }
27934 
27935   if (is_pinned) {
27936     contains_mention = !is_dialog_pinned_message_notifications_disabled(d);
27937   } else if (contains_mention && is_dialog_mention_notifications_disabled(d)) {
27938     contains_mention = false;
27939   }
27940   if (dialog_id.get_type() == DialogType::User) {
27941     contains_mention = false;
27942   }
27943 
27944   DialogId settings_dialog_id = dialog_id;
27945   Dialog *settings_dialog = d;
27946   if (contains_mention) {
27947     auto real_sender_dialog_id = sender_dialog_id.is_valid() ? sender_dialog_id : DialogId(sender_user_id);
27948     if (real_sender_dialog_id.is_valid()) {
27949       settings_dialog_id = real_sender_dialog_id;
27950       settings_dialog = get_dialog_force(settings_dialog_id, "get_message_push_notification_info");
27951     }
27952   }
27953 
27954   bool have_settings;
27955   int32 mute_until;
27956   std::tie(have_settings, mute_until) = get_dialog_mute_until(settings_dialog_id, settings_dialog);
27957   if (have_settings && mute_until > date) {
27958     if (is_new_pinned) {
27959       remove_dialog_pinned_message_notification(d, "get_message_push_notification_info");
27960     }
27961     return Status::Error("Ignore notification in muted chat");
27962   }
27963 
27964   if (is_dialog_message_notification_disabled(settings_dialog_id, date)) {
27965     if (is_new_pinned) {
27966       remove_dialog_pinned_message_notification(d, "get_message_push_notification_info");
27967     }
27968     return Status::Error("Ignore notification in chat, because notifications are disabled in the chat");
27969   }
27970 
27971   auto group_id = get_dialog_notification_group_id(
27972       dialog_id, contains_mention ? d->mention_notification_group : d->message_notification_group);
27973   if (!group_id.is_valid()) {
27974     return Status::Error("Can't assign notification group ID");
27975   }
27976 
27977   if (message_id.is_valid() && message_id > d->max_notification_message_id) {
27978     if (is_new_pinned) {
27979       set_dialog_pinned_message_notification(d, contains_mention ? message_id : MessageId(),
27980                                              "get_message_push_notification_info");
27981     }
27982     d->max_notification_message_id = message_id;
27983     on_dialog_updated(dialog_id, "set_max_notification_message_id");
27984   }
27985 
27986   MessagePushNotificationInfo result;
27987   result.group_id = group_id;
27988   result.group_type = contains_mention ? NotificationGroupType::Mentions : NotificationGroupType::Messages;
27989   result.settings_dialog_id = settings_dialog_id;
27990   return result;
27991 }
27992 
get_next_notification_id(Dialog * d,NotificationGroupId notification_group_id,MessageId message_id)27993 NotificationId MessagesManager::get_next_notification_id(Dialog *d, NotificationGroupId notification_group_id,
27994                                                          MessageId message_id) {
27995   CHECK(d != nullptr);
27996   CHECK(!message_id.is_scheduled());
27997   NotificationId notification_id;
27998   do {
27999     notification_id = td_->notification_manager_->get_next_notification_id();
28000     if (!notification_id.is_valid()) {
28001       return NotificationId();
28002     }
28003   } while (d->notification_id_to_message_id.count(notification_id) != 0 ||
28004            d->new_secret_chat_notification_id == notification_id ||
28005            notification_id.get() <= d->message_notification_group.last_notification_id.get() ||
28006            notification_id.get() <= d->message_notification_group.max_removed_notification_id.get() ||
28007            notification_id.get() <= d->mention_notification_group.last_notification_id.get() ||
28008            notification_id.get() <= d->mention_notification_group.max_removed_notification_id.get());  // just in case
28009   if (message_id.is_valid()) {
28010     add_notification_id_to_message_id_correspondence(d, notification_id, message_id);
28011   }
28012   return notification_id;
28013 }
28014 
get_message_notification_group_force(NotificationGroupId group_id)28015 MessagesManager::MessageNotificationGroup MessagesManager::get_message_notification_group_force(
28016     NotificationGroupId group_id) {
28017   CHECK(!td_->auth_manager_->is_bot());
28018   CHECK(group_id.is_valid());
28019   Dialog *d = nullptr;
28020   auto it = notification_group_id_to_dialog_id_.find(group_id);
28021   if (it != notification_group_id_to_dialog_id_.end()) {
28022     d = get_dialog(it->second);
28023     CHECK(d != nullptr);
28024   } else if (G()->parameters().use_message_db) {
28025     auto *dialog_db = G()->td_db()->get_dialog_db_sync();
28026     dialog_db->begin_read_transaction().ensure();
28027     auto r_value = dialog_db->get_notification_group(group_id);
28028     if (r_value.is_ok()) {
28029       VLOG(notifications) << "Loaded " << r_value.ok() << " from database by " << group_id;
28030       d = get_dialog_force(r_value.ok().dialog_id, "get_message_notification_group_force");
28031     } else {
28032       LOG_CHECK(r_value.error().message() == "Not found") << r_value.error();
28033       VLOG(notifications) << "Failed to load " << group_id << " from database";
28034     }
28035     dialog_db->commit_transaction().ensure();
28036   }
28037 
28038   if (d == nullptr) {
28039     return MessageNotificationGroup();
28040   }
28041   if (d->message_notification_group.group_id != group_id && d->mention_notification_group.group_id != group_id) {
28042     if (d->dialog_id.get_type() == DialogType::SecretChat && !d->message_notification_group.group_id.is_valid() &&
28043         !d->mention_notification_group.group_id.is_valid()) {
28044       // the group was reused, but wasn't deleted from the database, trying to resave it
28045       auto &group_info = d->message_notification_group;
28046       group_info.group_id = group_id;
28047       group_info.is_changed = true;
28048       group_info.try_reuse = true;
28049       save_dialog_to_database(d->dialog_id);
28050       group_info.group_id = NotificationGroupId();
28051       group_info.is_changed = false;
28052       group_info.try_reuse = false;
28053     }
28054   }
28055 
28056   LOG_CHECK(d->message_notification_group.group_id == group_id || d->mention_notification_group.group_id == group_id)
28057       << group_id << " " << d->message_notification_group.group_id << " " << d->mention_notification_group.group_id
28058       << " " << d->dialog_id << " " << notification_group_id_to_dialog_id_[group_id] << " "
28059       << notification_group_id_to_dialog_id_[d->message_notification_group.group_id] << " "
28060       << notification_group_id_to_dialog_id_[d->mention_notification_group.group_id];
28061 
28062   bool from_mentions = d->mention_notification_group.group_id == group_id;
28063   auto &group_info = from_mentions ? d->mention_notification_group : d->message_notification_group;
28064 
28065   MessageNotificationGroup result;
28066   VLOG(notifications) << "Found " << (from_mentions ? "Mentions " : "Messages ") << group_info.group_id << '/'
28067                       << d->dialog_id << " by " << group_id << " with " << d->unread_mention_count
28068                       << " unread mentions, pinned " << d->pinned_message_notification_message_id
28069                       << ", new secret chat " << d->new_secret_chat_notification_id << " and "
28070                       << d->server_unread_count + d->local_unread_count << " unread messages";
28071   result.dialog_id = d->dialog_id;
28072   result.total_count = get_dialog_pending_notification_count(d, from_mentions);
28073   auto pending_notification_count =
28074       from_mentions ? d->pending_new_mention_notifications.size() : d->pending_new_message_notifications.size();
28075   result.total_count -= static_cast<int32>(pending_notification_count);
28076   if (result.total_count < 0) {
28077     LOG(ERROR) << "Total notification count is " << result.total_count << " in " << d->dialog_id << " with "
28078                << pending_notification_count << " pending new notifications";
28079     result.total_count = 0;
28080   }
28081   if (d->new_secret_chat_notification_id.is_valid()) {
28082     CHECK(d->dialog_id.get_type() == DialogType::SecretChat);
28083     result.type = NotificationGroupType::SecretChat;
28084     result.notifications.emplace_back(d->new_secret_chat_notification_id,
28085                                       td_->contacts_manager_->get_secret_chat_date(d->dialog_id.get_secret_chat_id()),
28086                                       false, create_new_secret_chat_notification());
28087   } else {
28088     result.type = from_mentions ? NotificationGroupType::Mentions : NotificationGroupType::Messages;
28089     result.notifications = get_message_notifications_from_database_force(
28090         d, from_mentions, static_cast<int32>(td_->notification_manager_->get_max_notification_group_size()));
28091   }
28092 
28093   int32 last_notification_date = 0;
28094   NotificationId last_notification_id;
28095   if (!result.notifications.empty()) {
28096     last_notification_date = result.notifications[0].date;
28097     last_notification_id = result.notifications[0].notification_id;
28098   }
28099   if (last_notification_date != group_info.last_notification_date ||
28100       last_notification_id != group_info.last_notification_id) {
28101     LOG(ERROR) << "Fix last notification date in " << d->dialog_id << " from " << group_info.last_notification_date
28102                << " to " << last_notification_date << " and last notification identifier from "
28103                << group_info.last_notification_id << " to " << last_notification_id << " in " << group_id << " of type "
28104                << result.type;
28105     set_dialog_last_notification(d->dialog_id, group_info, last_notification_date, last_notification_id,
28106                                  "get_message_notification_group_force");
28107   }
28108 
28109   std::reverse(result.notifications.begin(), result.notifications.end());
28110 
28111   return result;
28112 }
28113 
is_from_mention_notification_group(const Dialog * d,const Message * m)28114 bool MessagesManager::is_from_mention_notification_group(const Dialog *d, const Message *m) {
28115   return m->contains_mention && !m->is_mention_notification_disabled;
28116 }
28117 
is_message_notification_active(const Dialog * d,const Message * m)28118 bool MessagesManager::is_message_notification_active(const Dialog *d, const Message *m) {
28119   CHECK(!m->message_id.is_scheduled());
28120   if (is_from_mention_notification_group(d, m)) {
28121     return m->notification_id.get() > d->mention_notification_group.max_removed_notification_id.get() &&
28122            m->message_id > d->mention_notification_group.max_removed_message_id &&
28123            (m->contains_unread_mention || m->message_id == d->pinned_message_notification_message_id);
28124   } else {
28125     return m->notification_id.get() > d->message_notification_group.max_removed_notification_id.get() &&
28126            m->message_id > d->message_notification_group.max_removed_message_id &&
28127            m->message_id > d->last_read_inbox_message_id;
28128   }
28129 }
28130 
try_add_pinned_message_notification(Dialog * d,vector<Notification> & res,NotificationId max_notification_id,int32 limit)28131 void MessagesManager::try_add_pinned_message_notification(Dialog *d, vector<Notification> &res,
28132                                                           NotificationId max_notification_id, int32 limit) {
28133   CHECK(d != nullptr);
28134   auto message_id = d->pinned_message_notification_message_id;
28135   if (!message_id.is_valid() || message_id > d->last_new_message_id) {
28136     CHECK(!message_id.is_scheduled());
28137     return;
28138   }
28139 
28140   auto m = get_message_force(d, message_id, "try_add_pinned_message_notification");
28141   if (m != nullptr && m->notification_id.get() > d->mention_notification_group.max_removed_notification_id.get() &&
28142       m->message_id > d->mention_notification_group.max_removed_message_id &&
28143       m->message_id > d->last_read_inbox_message_id && !is_dialog_pinned_message_notifications_disabled(d)) {
28144     if (m->notification_id.get() < max_notification_id.get()) {
28145       VLOG(notifications) << "Add " << m->notification_id << " about pinned " << message_id << " in " << d->dialog_id;
28146       auto pinned_message_id = get_message_content_pinned_message_id(m->content.get());
28147       if (pinned_message_id.is_valid()) {
28148         get_message_force(d, pinned_message_id, "try_add_pinned_message_notification 2");  // preload pinned message
28149       }
28150 
28151       auto pos = res.size();
28152       res.emplace_back(m->notification_id, m->date, m->disable_notification,
28153                        create_new_message_notification(message_id));
28154       while (pos > 0 && res[pos - 1].type->get_message_id() < message_id) {
28155         std::swap(res[pos - 1], res[pos]);
28156         pos--;
28157       }
28158       if (pos > 0 && res[pos - 1].type->get_message_id() == message_id) {
28159         res.erase(res.begin() + pos);  // notification was already there
28160       }
28161       if (res.size() > static_cast<size_t>(limit)) {
28162         res.pop_back();
28163         CHECK(res.size() == static_cast<size_t>(limit));
28164       }
28165     }
28166   } else {
28167     remove_dialog_pinned_message_notification(d, "try_add_pinned_message_notification");
28168   }
28169 }
28170 
get_message_notifications_from_database_force(Dialog * d,bool from_mentions,int32 limit)28171 vector<Notification> MessagesManager::get_message_notifications_from_database_force(Dialog *d, bool from_mentions,
28172                                                                                     int32 limit) {
28173   CHECK(d != nullptr);
28174   if (!G()->parameters().use_message_db || td_->auth_manager_->is_bot()) {
28175     return {};
28176   }
28177 
28178   auto &group_info = from_mentions ? d->mention_notification_group : d->message_notification_group;
28179   auto from_notification_id = NotificationId::max();
28180   auto from_message_id = MessageId::max();
28181   vector<Notification> res;
28182   if (!from_mentions && from_message_id <= d->last_read_inbox_message_id) {
28183     return res;
28184   }
28185   while (true) {
28186     auto result = do_get_message_notifications_from_database_force(d, from_mentions, from_notification_id,
28187                                                                    from_message_id, limit);
28188     if (result.is_error()) {
28189       break;
28190     }
28191     auto messages = result.move_as_ok();
28192     if (messages.empty()) {
28193       break;
28194     }
28195 
28196     bool is_found = false;
28197     VLOG(notifications) << "Loaded " << messages.size() << (from_mentions ? " mention" : "")
28198                         << " messages with notifications from database in " << group_info.group_id << '/'
28199                         << d->dialog_id;
28200     for (auto &message : messages) {
28201       auto m = on_get_message_from_database(d, message, false, "get_message_notifications_from_database_force");
28202       if (m == nullptr) {
28203         VLOG(notifications) << "Receive from database a broken message";
28204         continue;
28205       }
28206 
28207       auto notification_id = m->notification_id.is_valid() ? m->notification_id : m->removed_notification_id;
28208       if (!notification_id.is_valid()) {
28209         LOG(ERROR) << "Can't find notification identifier for " << m->message_id << " in " << d->dialog_id
28210                    << " with from_mentions = " << from_mentions;
28211         continue;
28212       }
28213       CHECK(m->message_id.is_valid());
28214 
28215       bool is_correct = true;
28216       if (notification_id.get() >= from_notification_id.get()) {
28217         // possible if two messages have the same notification_id
28218         LOG(ERROR) << "Have nonmonotonic notification identifiers: " << d->dialog_id << " " << m->message_id << " "
28219                    << notification_id << " " << from_message_id << " " << from_notification_id;
28220         is_correct = false;
28221       } else {
28222         from_notification_id = notification_id;
28223         is_found = true;
28224       }
28225       if (m->message_id >= from_message_id) {
28226         LOG(ERROR) << "Have nonmonotonic message identifiers: " << d->dialog_id << " " << m->message_id << " "
28227                    << notification_id << " " << from_message_id << " " << from_notification_id;
28228         is_correct = false;
28229       } else {
28230         from_message_id = m->message_id;
28231         is_found = true;
28232       }
28233 
28234       if (notification_id.get() <= group_info.max_removed_notification_id.get() ||
28235           m->message_id <= group_info.max_removed_message_id ||
28236           (!from_mentions && m->message_id <= d->last_read_inbox_message_id)) {
28237         // if message still has notification_id, but it was removed via max_removed_notification_id,
28238         // or max_removed_message_id, or last_read_inbox_message_id,
28239         // then there will be no more messages with active notifications
28240         is_found = false;
28241         break;
28242       }
28243 
28244       if (!m->notification_id.is_valid()) {
28245         // notification_id can be empty if it is deleted in memory, but not in the database
28246         VLOG(notifications) << "Receive from database " << m->message_id << " with removed "
28247                             << m->removed_notification_id;
28248         continue;
28249       }
28250 
28251       if (is_from_mention_notification_group(d, m) != from_mentions) {
28252         VLOG(notifications) << "Receive from database " << m->message_id << " with " << m->notification_id
28253                             << " from another group";
28254         continue;
28255       }
28256 
28257       if (!is_message_notification_active(d, m)) {
28258         CHECK(from_mentions);
28259         CHECK(!m->contains_unread_mention);
28260         CHECK(m->message_id != d->pinned_message_notification_message_id);
28261         // skip read mentions
28262         continue;
28263       }
28264 
28265       if (is_correct) {
28266         // skip mention messages returned among unread messages
28267         res.emplace_back(m->notification_id, m->date, m->disable_notification,
28268                          create_new_message_notification(m->message_id));
28269       } else {
28270         remove_message_notification_id(d, m, true, false);
28271         on_message_changed(d, m, false, "get_message_notifications_from_database_force");
28272       }
28273     }
28274     if (!res.empty() || !is_found) {
28275       break;
28276     }
28277   }
28278   if (from_mentions) {
28279     try_add_pinned_message_notification(d, res, NotificationId::max(), limit);
28280   }
28281   return res;
28282 }
28283 
do_get_message_notifications_from_database_force(Dialog * d,bool from_mentions,NotificationId from_notification_id,MessageId from_message_id,int32 limit)28284 Result<vector<MessagesDbDialogMessage>> MessagesManager::do_get_message_notifications_from_database_force(
28285     Dialog *d, bool from_mentions, NotificationId from_notification_id, MessageId from_message_id, int32 limit) {
28286   CHECK(G()->parameters().use_message_db);
28287   CHECK(!from_message_id.is_scheduled());
28288 
28289   auto *db = G()->td_db()->get_messages_db_sync();
28290   if (!from_mentions) {
28291     CHECK(from_message_id > d->last_read_inbox_message_id);
28292     VLOG(notifications) << "Trying to load " << limit << " messages with notifications in "
28293                         << d->message_notification_group.group_id << '/' << d->dialog_id << " from "
28294                         << from_notification_id;
28295     return db->get_messages_from_notification_id(d->dialog_id, from_notification_id, limit);
28296   } else {
28297     VLOG(notifications) << "Trying to load " << limit << " messages with unread mentions in "
28298                         << d->mention_notification_group.group_id << '/' << d->dialog_id << " from " << from_message_id;
28299 
28300     // ignore first_db_message_id, notifications can be nonconsecutive
28301     MessagesDbMessagesQuery db_query;
28302     db_query.dialog_id = d->dialog_id;
28303     db_query.filter = MessageSearchFilter::UnreadMention;
28304     db_query.from_message_id = from_message_id;
28305     db_query.offset = 0;
28306     db_query.limit = limit;
28307     return db->get_messages(db_query);
28308   }
28309 }
28310 
get_message_notification_group_keys_from_database(NotificationGroupKey from_group_key,int32 limit)28311 vector<NotificationGroupKey> MessagesManager::get_message_notification_group_keys_from_database(
28312     NotificationGroupKey from_group_key, int32 limit) {
28313   if (!G()->parameters().use_message_db) {
28314     return {};
28315   }
28316 
28317   VLOG(notifications) << "Trying to load " << limit << " message notification groups from database from "
28318                       << from_group_key;
28319 
28320   auto *dialog_db = G()->td_db()->get_dialog_db_sync();
28321   dialog_db->begin_read_transaction().ensure();
28322   Result<vector<NotificationGroupKey>> r_notification_group_keys =
28323       dialog_db->get_notification_groups_by_last_notification_date(from_group_key, limit);
28324   r_notification_group_keys.ensure();
28325   auto group_keys = r_notification_group_keys.move_as_ok();
28326 
28327   vector<NotificationGroupKey> result;
28328   for (auto &group_key : group_keys) {
28329     CHECK(group_key.dialog_id.is_valid());
28330     const Dialog *d = get_dialog_force(group_key.dialog_id, "get_message_notification_group_keys_from_database");
28331     if (d == nullptr || (d->message_notification_group.group_id != group_key.group_id &&
28332                          d->mention_notification_group.group_id != group_key.group_id)) {
28333       continue;
28334     }
28335 
28336     CHECK(d->dialog_id == group_key.dialog_id);
28337     CHECK(notification_group_id_to_dialog_id_[group_key.group_id] == d->dialog_id);
28338 
28339     VLOG(notifications) << "Loaded " << group_key << " from database";
28340     result.push_back(group_key);
28341   }
28342   dialog_db->commit_transaction().ensure();
28343   return result;
28344 }
28345 
get_message_notifications_from_database(DialogId dialog_id,NotificationGroupId group_id,NotificationId from_notification_id,MessageId from_message_id,int32 limit,Promise<vector<Notification>> promise)28346 void MessagesManager::get_message_notifications_from_database(DialogId dialog_id, NotificationGroupId group_id,
28347                                                               NotificationId from_notification_id,
28348                                                               MessageId from_message_id, int32 limit,
28349                                                               Promise<vector<Notification>> promise) {
28350   if (!G()->parameters().use_message_db) {
28351     return promise.set_error(Status::Error(500, "There is no message database"));
28352   }
28353   if (td_->auth_manager_->is_bot()) {
28354     return promise.set_error(Status::Error(500, "Bots have no notifications"));
28355   }
28356 
28357   CHECK(dialog_id.is_valid());
28358   CHECK(group_id.is_valid());
28359   CHECK(!from_message_id.is_scheduled());
28360   CHECK(limit > 0);
28361 
28362   auto d = get_dialog(dialog_id);
28363   CHECK(d != nullptr);
28364   if (d->message_notification_group.group_id != group_id && d->mention_notification_group.group_id != group_id) {
28365     return promise.set_value(vector<Notification>());
28366   }
28367 
28368   VLOG(notifications) << "Get " << limit << " message notifications from database in " << group_id << " from "
28369                       << dialog_id << " from " << from_notification_id << "/" << from_message_id;
28370   bool from_mentions = d->mention_notification_group.group_id == group_id;
28371   if (d->new_secret_chat_notification_id.is_valid()) {
28372     CHECK(dialog_id.get_type() == DialogType::SecretChat);
28373     vector<Notification> notifications;
28374     if (!from_mentions && d->new_secret_chat_notification_id.get() < from_notification_id.get()) {
28375       auto date = td_->contacts_manager_->get_secret_chat_date(dialog_id.get_secret_chat_id());
28376       if (date <= 0) {
28377         remove_new_secret_chat_notification(d, true);
28378       } else {
28379         notifications.emplace_back(d->new_secret_chat_notification_id, date, false,
28380                                    create_new_secret_chat_notification());
28381       }
28382     }
28383     return promise.set_value(std::move(notifications));
28384   }
28385 
28386   do_get_message_notifications_from_database(d, from_mentions, from_notification_id, from_notification_id,
28387                                              from_message_id, limit, std::move(promise));
28388 }
28389 
do_get_message_notifications_from_database(Dialog * d,bool from_mentions,NotificationId initial_from_notification_id,NotificationId from_notification_id,MessageId from_message_id,int32 limit,Promise<vector<Notification>> promise)28390 void MessagesManager::do_get_message_notifications_from_database(Dialog *d, bool from_mentions,
28391                                                                  NotificationId initial_from_notification_id,
28392                                                                  NotificationId from_notification_id,
28393                                                                  MessageId from_message_id, int32 limit,
28394                                                                  Promise<vector<Notification>> promise) {
28395   CHECK(G()->parameters().use_message_db);
28396   CHECK(!from_message_id.is_scheduled());
28397 
28398   auto &group_info = from_mentions ? d->mention_notification_group : d->message_notification_group;
28399   if (from_notification_id.get() <= group_info.max_removed_notification_id.get() ||
28400       from_message_id <= group_info.max_removed_message_id ||
28401       (!from_mentions && from_message_id <= d->last_read_inbox_message_id)) {
28402     return promise.set_value(vector<Notification>());
28403   }
28404 
28405   auto dialog_id = d->dialog_id;
28406   auto new_promise =
28407       PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, from_mentions, initial_from_notification_id, limit,
28408                               promise = std::move(promise)](Result<vector<MessagesDbDialogMessage>> result) mutable {
28409         send_closure(actor_id, &MessagesManager::on_get_message_notifications_from_database, dialog_id, from_mentions,
28410                      initial_from_notification_id, limit, std::move(result), std::move(promise));
28411       });
28412 
28413   auto *db = G()->td_db()->get_messages_db_async();
28414   if (!from_mentions) {
28415     VLOG(notifications) << "Trying to load " << limit << " messages with notifications in " << group_info.group_id
28416                         << '/' << dialog_id << " from " << from_notification_id;
28417     return db->get_messages_from_notification_id(d->dialog_id, from_notification_id, limit, std::move(new_promise));
28418   } else {
28419     VLOG(notifications) << "Trying to load " << limit << " messages with unread mentions in " << group_info.group_id
28420                         << '/' << dialog_id << " from " << from_message_id;
28421 
28422     // ignore first_db_message_id, notifications can be nonconsecutive
28423     MessagesDbMessagesQuery db_query;
28424     db_query.dialog_id = dialog_id;
28425     db_query.filter = MessageSearchFilter::UnreadMention;
28426     db_query.from_message_id = from_message_id;
28427     db_query.offset = 0;
28428     db_query.limit = limit;
28429     return db->get_messages(db_query, std::move(new_promise));
28430   }
28431 }
28432 
on_get_message_notifications_from_database(DialogId dialog_id,bool from_mentions,NotificationId initial_from_notification_id,int32 limit,Result<vector<MessagesDbDialogMessage>> result,Promise<vector<Notification>> promise)28433 void MessagesManager::on_get_message_notifications_from_database(DialogId dialog_id, bool from_mentions,
28434                                                                  NotificationId initial_from_notification_id,
28435                                                                  int32 limit,
28436                                                                  Result<vector<MessagesDbDialogMessage>> result,
28437                                                                  Promise<vector<Notification>> promise) {
28438   if (G()->close_flag()) {
28439     result = Global::request_aborted_error();
28440   }
28441   if (result.is_error()) {
28442     return promise.set_error(result.move_as_error());
28443   }
28444 
28445   Dialog *d = get_dialog(dialog_id);
28446   CHECK(d != nullptr);
28447 
28448   auto &group_info = from_mentions ? d->mention_notification_group : d->message_notification_group;
28449   if (!group_info.group_id.is_valid()) {
28450     return promise.set_error(Status::Error("Notification group was deleted"));
28451   }
28452 
28453   auto messages = result.move_as_ok();
28454   vector<Notification> res;
28455   res.reserve(messages.size());
28456   NotificationId from_notification_id;
28457   MessageId from_message_id;
28458   VLOG(notifications) << "Loaded " << messages.size() << " messages with notifications in " << group_info.group_id
28459                       << '/' << dialog_id << " from database";
28460   for (auto &message : messages) {
28461     auto m = on_get_message_from_database(d, message, false, "on_get_message_notifications_from_database");
28462     if (m == nullptr) {
28463       VLOG(notifications) << "Receive from database a broken message";
28464       continue;
28465     }
28466 
28467     auto notification_id = m->notification_id.is_valid() ? m->notification_id : m->removed_notification_id;
28468     if (!notification_id.is_valid()) {
28469       LOG(ERROR) << "Can't find notification identifier for " << m->message_id << " in " << d->dialog_id
28470                  << " with from_mentions = " << from_mentions;
28471       continue;
28472     }
28473     CHECK(m->message_id.is_valid());
28474 
28475     bool is_correct = true;
28476     if (from_notification_id.is_valid() && notification_id.get() >= from_notification_id.get()) {
28477       LOG(ERROR) << "Receive " << m->message_id << "/" << notification_id << " after " << from_message_id << "/"
28478                  << from_notification_id;
28479       is_correct = false;
28480     } else {
28481       from_notification_id = notification_id;
28482     }
28483     if (from_message_id.is_valid() && m->message_id >= from_message_id) {
28484       LOG(ERROR) << "Receive " << m->message_id << "/" << notification_id << " after " << from_message_id << "/"
28485                  << from_notification_id;
28486       is_correct = false;
28487     } else {
28488       from_message_id = m->message_id;
28489     }
28490 
28491     if (notification_id.get() <= group_info.max_removed_notification_id.get() ||
28492         m->message_id <= group_info.max_removed_message_id ||
28493         (!from_mentions && m->message_id <= d->last_read_inbox_message_id)) {
28494       // if message still has notification_id, but it was removed via max_removed_notification_id,
28495       // or max_removed_message_id, or last_read_inbox_message_id,
28496       // then there will be no more messages with active notifications
28497       from_notification_id = NotificationId();  // stop requesting database
28498       break;
28499     }
28500 
28501     if (!m->notification_id.is_valid()) {
28502       // notification_id can be empty if it is deleted in memory, but not in the database
28503       VLOG(notifications) << "Receive from database " << m->message_id << " with removed "
28504                           << m->removed_notification_id;
28505       continue;
28506     }
28507 
28508     if (is_from_mention_notification_group(d, m) != from_mentions) {
28509       VLOG(notifications) << "Receive from database " << m->message_id << " with " << m->notification_id
28510                           << " from another category";
28511       continue;
28512     }
28513 
28514     if (!is_message_notification_active(d, m)) {
28515       CHECK(from_mentions);
28516       CHECK(!m->contains_unread_mention);
28517       CHECK(m->message_id != d->pinned_message_notification_message_id);
28518       // skip read mentions
28519       continue;
28520     }
28521 
28522     if (is_correct) {
28523       // skip mention messages returned among unread messages
28524       CHECK(m->date > 0);
28525       res.emplace_back(m->notification_id, m->date, m->disable_notification,
28526                        create_new_message_notification(m->message_id));
28527     } else {
28528       remove_message_notification_id(d, m, true, false);
28529       on_message_changed(d, m, false, "on_get_message_notifications_from_database");
28530     }
28531   }
28532   if (!res.empty() || !from_notification_id.is_valid() || static_cast<size_t>(limit) > messages.size()) {
28533     if (from_mentions) {
28534       try_add_pinned_message_notification(d, res, initial_from_notification_id, limit);
28535     }
28536 
28537     std::reverse(res.begin(), res.end());
28538     return promise.set_value(std::move(res));
28539   }
28540 
28541   // try again from adjusted from_notification_id and from_message_id
28542   do_get_message_notifications_from_database(d, from_mentions, initial_from_notification_id, from_notification_id,
28543                                              from_message_id, limit, std::move(promise));
28544 }
28545 
remove_message_notification(DialogId dialog_id,NotificationGroupId group_id,NotificationId notification_id)28546 void MessagesManager::remove_message_notification(DialogId dialog_id, NotificationGroupId group_id,
28547                                                   NotificationId notification_id) {
28548   Dialog *d = get_dialog_force(dialog_id, "remove_message_notification");
28549   if (d == nullptr) {
28550     LOG(ERROR) << "Can't find " << dialog_id;
28551     return;
28552   }
28553   if (d->message_notification_group.group_id != group_id && d->mention_notification_group.group_id != group_id) {
28554     LOG(ERROR) << "There is no " << group_id << " in " << dialog_id;
28555     return;
28556   }
28557   if (notification_id == NotificationId::max() || !notification_id.is_valid()) {
28558     return;  // there can be no notification with this ID
28559   }
28560 
28561   bool from_mentions = d->mention_notification_group.group_id == group_id;
28562   if (d->new_secret_chat_notification_id.is_valid()) {
28563     if (!from_mentions && d->new_secret_chat_notification_id == notification_id) {
28564       return remove_new_secret_chat_notification(d, false);
28565     }
28566     return;
28567   }
28568 
28569   auto it = d->notification_id_to_message_id.find(notification_id);
28570   if (it != d->notification_id_to_message_id.end()) {
28571     auto m = get_message(d, it->second);
28572     CHECK(m != nullptr);
28573     CHECK(m->notification_id == notification_id);
28574     CHECK(!m->message_id.is_scheduled());
28575     if (is_from_mention_notification_group(d, m) == from_mentions && is_message_notification_active(d, m)) {
28576       remove_message_notification_id(d, m, false, false);
28577     }
28578     return;
28579   }
28580 
28581   if (G()->parameters().use_message_db) {
28582     G()->td_db()->get_messages_db_async()->get_messages_from_notification_id(
28583         dialog_id, NotificationId(notification_id.get() + 1), 1,
28584         PromiseCreator::lambda([dialog_id, from_mentions, notification_id,
28585                                 actor_id = actor_id(this)](vector<MessagesDbDialogMessage> result) {
28586           send_closure(actor_id, &MessagesManager::do_remove_message_notification, dialog_id, from_mentions,
28587                        notification_id, std::move(result));
28588         }));
28589   }
28590 }
28591 
remove_message_notifications_by_message_ids(DialogId dialog_id,const vector<MessageId> & message_ids)28592 void MessagesManager::remove_message_notifications_by_message_ids(DialogId dialog_id,
28593                                                                   const vector<MessageId> &message_ids) {
28594   VLOG(notifications) << "Trying to remove notification about " << message_ids << " in " << dialog_id;
28595   Dialog *d = get_dialog_force(dialog_id, "remove_message_notifications_by_message_ids");
28596   if (d == nullptr) {
28597     return;
28598   }
28599 
28600   bool need_update_dialog_pos = false;
28601   vector<int64> deleted_message_ids;
28602   for (auto message_id : message_ids) {
28603     CHECK(!message_id.is_scheduled());
28604     // can't remove just notification_id, because total_count will stay wrong after restart
28605     // delete whole message
28606     auto message =
28607         delete_message(d, message_id, true, &need_update_dialog_pos, "remove_message_notifications_by_message_ids");
28608     if (message == nullptr) {
28609       LOG(INFO) << "Can't delete " << message_id << " because it is not found";
28610       // call synchronously to remove them before ProcessPush returns
28611       td_->notification_manager_->remove_temporary_notification_by_message_id(
28612           d->message_notification_group.group_id, message_id, true, "remove_message_notifications_by_message_ids");
28613       td_->notification_manager_->remove_temporary_notification_by_message_id(
28614           d->mention_notification_group.group_id, message_id, true, "remove_message_notifications_by_message_ids");
28615       continue;
28616     }
28617     deleted_message_ids.push_back(message->message_id.get());
28618   }
28619 
28620   if (need_update_dialog_pos) {
28621     send_update_chat_last_message(d, "remove_message_notifications_by_message_ids");
28622   }
28623   send_update_delete_messages(dialog_id, std::move(deleted_message_ids), true, false);
28624 }
28625 
do_remove_message_notification(DialogId dialog_id,bool from_mentions,NotificationId notification_id,vector<MessagesDbDialogMessage> result)28626 void MessagesManager::do_remove_message_notification(DialogId dialog_id, bool from_mentions,
28627                                                      NotificationId notification_id,
28628                                                      vector<MessagesDbDialogMessage> result) {
28629   if (result.empty() || G()->close_flag()) {
28630     return;
28631   }
28632   CHECK(result.size() == 1);
28633 
28634   Dialog *d = get_dialog(dialog_id);
28635   CHECK(d != nullptr);
28636 
28637   auto m = on_get_message_from_database(d, result[0], false, "do_remove_message_notification");
28638   if (m != nullptr && m->notification_id == notification_id &&
28639       is_from_mention_notification_group(d, m) == from_mentions && is_message_notification_active(d, m)) {
28640     remove_message_notification_id(d, m, false, false);
28641   }
28642 }
28643 
remove_message_notifications(DialogId dialog_id,NotificationGroupId group_id,NotificationId max_notification_id,MessageId max_message_id)28644 void MessagesManager::remove_message_notifications(DialogId dialog_id, NotificationGroupId group_id,
28645                                                    NotificationId max_notification_id, MessageId max_message_id) {
28646   Dialog *d = get_dialog_force(dialog_id, "remove_message_notifications");
28647   if (d == nullptr) {
28648     LOG(ERROR) << "Can't find " << dialog_id;
28649     return;
28650   }
28651   if (d->message_notification_group.group_id != group_id && d->mention_notification_group.group_id != group_id) {
28652     LOG(ERROR) << "There is no " << group_id << " in " << dialog_id;
28653     return;
28654   }
28655   if (!max_notification_id.is_valid()) {
28656     return;
28657   }
28658   CHECK(!max_message_id.is_scheduled());
28659 
28660   bool from_mentions = d->mention_notification_group.group_id == group_id;
28661   if (d->new_secret_chat_notification_id.is_valid()) {
28662     if (!from_mentions && d->new_secret_chat_notification_id.get() <= max_notification_id.get()) {
28663       return remove_new_secret_chat_notification(d, false);
28664     }
28665     return;
28666   }
28667   auto &group_info = from_mentions ? d->mention_notification_group : d->message_notification_group;
28668   if (max_notification_id.get() <= group_info.max_removed_notification_id.get()) {
28669     return;
28670   }
28671   if (max_message_id > group_info.max_removed_message_id) {
28672     VLOG(notifications) << "Set max_removed_message_id in " << group_info.group_id << '/' << dialog_id << " to "
28673                         << max_message_id;
28674     group_info.max_removed_message_id = max_message_id.get_prev_server_message_id();
28675   }
28676 
28677   VLOG(notifications) << "Set max_removed_notification_id in " << group_info.group_id << '/' << dialog_id << " to "
28678                       << max_notification_id;
28679   group_info.max_removed_notification_id = max_notification_id;
28680   on_dialog_updated(dialog_id, "remove_message_notifications");
28681 
28682   if (group_info.last_notification_id.is_valid() &&
28683       max_notification_id.get() >= group_info.last_notification_id.get()) {
28684     bool is_changed =
28685         set_dialog_last_notification(dialog_id, group_info, 0, NotificationId(), "remove_message_notifications");
28686     CHECK(is_changed);
28687   }
28688 }
28689 
get_dialog_pending_notification_count(const Dialog * d,bool from_mentions) const28690 int32 MessagesManager::get_dialog_pending_notification_count(const Dialog *d, bool from_mentions) const {
28691   CHECK(!td_->auth_manager_->is_bot());
28692   CHECK(d != nullptr);
28693   if (from_mentions) {
28694     bool has_pinned_message = d->pinned_message_notification_message_id.is_valid() &&
28695                               d->pinned_message_notification_message_id <= d->last_new_message_id;
28696     return d->unread_mention_count + static_cast<int32>(has_pinned_message);
28697   } else {
28698     if (d->new_secret_chat_notification_id.is_valid()) {
28699       return 1;
28700     }
28701     if (is_dialog_muted(d)) {
28702       return narrow_cast<int32>(d->pending_new_message_notifications.size());  // usually 0
28703     }
28704 
28705     return d->server_unread_count + d->local_unread_count;
28706   }
28707 }
28708 
update_dialog_mention_notification_count(const Dialog * d)28709 void MessagesManager::update_dialog_mention_notification_count(const Dialog *d) {
28710   CHECK(d != nullptr);
28711   if (td_->auth_manager_->is_bot() || !d->mention_notification_group.group_id.is_valid()) {
28712     return;
28713   }
28714   auto total_count =
28715       get_dialog_pending_notification_count(d, true) - static_cast<int32>(d->pending_new_mention_notifications.size());
28716   if (total_count < 0) {
28717     LOG(ERROR) << "Total mention notification count is " << total_count << " in " << d->dialog_id << " with "
28718                << d->pending_new_mention_notifications << " pending new mention notifications";
28719     total_count = 0;
28720   }
28721   send_closure_later(G()->notification_manager(), &NotificationManager::set_notification_total_count,
28722                      d->mention_notification_group.group_id, total_count);
28723 }
28724 
is_message_notification_disabled(const Dialog * d,const Message * m) const28725 bool MessagesManager::is_message_notification_disabled(const Dialog *d, const Message *m) const {
28726   CHECK(d != nullptr);
28727   CHECK(m != nullptr);
28728 
28729   if (!has_incoming_notification(d->dialog_id, m) || td_->auth_manager_->is_bot()) {
28730     return true;
28731   }
28732   if (m->is_from_scheduled && d->dialog_id != get_my_dialog_id() &&
28733       G()->shared_config().get_option_boolean("disable_sent_scheduled_message_notifications")) {
28734     return true;
28735   }
28736   if (m->forward_info != nullptr && m->forward_info->is_imported) {
28737     return true;
28738   }
28739 
28740   switch (m->content->get_type()) {
28741     case MessageContentType::ChatDeleteHistory:
28742     case MessageContentType::ChatMigrateTo:
28743     case MessageContentType::Unsupported:
28744     case MessageContentType::ExpiredPhoto:
28745     case MessageContentType::ExpiredVideo:
28746     case MessageContentType::PassportDataSent:
28747     case MessageContentType::PassportDataReceived:
28748       VLOG(notifications) << "Disable notification for " << m->message_id << " in " << d->dialog_id
28749                           << " with content of type " << m->content->get_type();
28750       return true;
28751     case MessageContentType::ContactRegistered:
28752       if (m->disable_notification) {
28753         return true;
28754       }
28755       break;
28756     default:
28757       break;
28758   }
28759 
28760   return is_dialog_message_notification_disabled(d->dialog_id, m->date);
28761 }
28762 
is_dialog_message_notification_disabled(DialogId dialog_id,int32 message_date) const28763 bool MessagesManager::is_dialog_message_notification_disabled(DialogId dialog_id, int32 message_date) const {
28764   switch (dialog_id.get_type()) {
28765     case DialogType::User:
28766       break;
28767     case DialogType::Chat:
28768       if (!td_->contacts_manager_->get_chat_is_active(dialog_id.get_chat_id())) {
28769         return true;
28770       }
28771       break;
28772     case DialogType::Channel:
28773       if (!td_->contacts_manager_->get_channel_status(dialog_id.get_channel_id()).is_member() ||
28774           message_date < td_->contacts_manager_->get_channel_date(dialog_id.get_channel_id())) {
28775         return true;
28776       }
28777       break;
28778     case DialogType::SecretChat:
28779       if (td_->contacts_manager_->get_secret_chat_state(dialog_id.get_secret_chat_id()) == SecretChatState::Closed) {
28780         return true;
28781       }
28782       break;
28783     case DialogType::None:
28784     default:
28785       UNREACHABLE();
28786   }
28787   if (message_date < authorization_date_) {
28788     return true;
28789   }
28790 
28791   return false;
28792 }
28793 
may_need_message_notification(const Dialog * d,const Message * m) const28794 bool MessagesManager::may_need_message_notification(const Dialog *d, const Message *m) const {
28795   CHECK(d != nullptr);
28796   CHECK(m != nullptr);
28797   CHECK(m->message_id.is_valid());
28798 
28799   if (is_message_notification_disabled(d, m)) {
28800     return false;
28801   }
28802 
28803   if (is_from_mention_notification_group(d, m)) {
28804     return true;
28805   }
28806 
28807   bool have_settings;
28808   int32 mute_until;
28809   std::tie(have_settings, mute_until) = get_dialog_mute_until(d->dialog_id, d);
28810   return !have_settings || mute_until <= m->date;
28811 }
28812 
add_new_message_notification(Dialog * d,Message * m,bool force)28813 bool MessagesManager::add_new_message_notification(Dialog *d, Message *m, bool force) {
28814   CHECK(d != nullptr);
28815   CHECK(m != nullptr);
28816   CHECK(m->message_id.is_valid());
28817 
28818   if (!force) {
28819     if (d->message_notification_group.group_id.is_valid()) {
28820       send_closure_later(G()->notification_manager(), &NotificationManager::remove_temporary_notifications,
28821                          d->message_notification_group.group_id, "add_new_message_notification 1");
28822     }
28823     if (d->mention_notification_group.group_id.is_valid()) {
28824       send_closure_later(G()->notification_manager(), &NotificationManager::remove_temporary_notifications,
28825                          d->mention_notification_group.group_id, "add_new_message_notification 2");
28826     }
28827   }
28828 
28829   CHECK(!m->notification_id.is_valid());
28830   if (is_message_notification_disabled(d, m)) {
28831     return false;
28832   }
28833 
28834   auto from_mentions = is_from_mention_notification_group(d, m);
28835   bool is_pinned = m->content->get_type() == MessageContentType::PinMessage;
28836   bool is_active =
28837       from_mentions ? m->contains_unread_mention || is_pinned : m->message_id > d->last_read_inbox_message_id;
28838   if (is_active) {
28839     auto &group = from_mentions ? d->mention_notification_group : d->message_notification_group;
28840     if (group.max_removed_message_id >= m->message_id) {
28841       is_active = false;
28842     }
28843   }
28844   if (!is_active) {
28845     VLOG(notifications) << "Disable inactive notification for " << m->message_id << " in " << d->dialog_id;
28846     if (is_pinned) {
28847       remove_dialog_pinned_message_notification(d, "add_new_message_notification");
28848     }
28849     return false;
28850   }
28851 
28852   VLOG(notifications) << "Trying to " << (force ? "forcely " : "") << "add new message notification for "
28853                       << m->message_id << " in " << d->dialog_id
28854                       << (m->disable_notification ? " silently" : " with sound");
28855 
28856   DialogId settings_dialog_id = d->dialog_id;
28857   Dialog *settings_dialog = d;
28858   if (m->contains_mention && !m->is_mention_notification_disabled) {
28859     // have a mention, so use notification settings from the dialog with the sender
28860     auto sender_dialog_id = get_message_sender(m);
28861     if (sender_dialog_id.is_valid()) {
28862       settings_dialog_id = sender_dialog_id;
28863       settings_dialog = get_dialog_force(settings_dialog_id, "add_new_message_notification");
28864     }
28865   }
28866 
28867   bool have_settings;
28868   int32 mute_until;
28869   std::tie(have_settings, mute_until) = get_dialog_mute_until(settings_dialog_id, settings_dialog);
28870   if (mute_until > m->date && (have_settings || force)) {
28871     VLOG(notifications) << "Disable notification, because " << settings_dialog_id << " is muted";
28872     if (is_pinned) {
28873       remove_dialog_pinned_message_notification(d, "add_new_message_notification");
28874     }
28875     return false;
28876   }
28877 
28878   MessageId missing_pinned_message_id;
28879   if (is_pinned) {
28880     auto message_id = get_message_content_pinned_message_id(m->content.get());
28881     if (message_id.is_valid() &&
28882         !have_message_force(d, message_id,
28883                             force ? "add_new_message_notification force" : "add_new_message_notification not force")) {
28884       missing_pinned_message_id = message_id;
28885     }
28886   }
28887 
28888   auto &pending_notifications =
28889       from_mentions ? d->pending_new_mention_notifications : d->pending_new_message_notifications;
28890   if (!force && (!have_settings || !pending_notifications.empty() || missing_pinned_message_id.is_valid())) {
28891     VLOG(notifications) << "Delay new message notification for " << m->message_id << " in " << d->dialog_id << " with "
28892                         << pending_notifications.size() << " already waiting messages";
28893     if (pending_notifications.empty()) {
28894       VLOG(notifications) << "Create FlushPendingNewMessageNotificationsSleepActor for " << d->dialog_id;
28895       create_actor<SleepActor>("FlushPendingNewMessageNotificationsSleepActor", 5.0,
28896                                PromiseCreator::lambda([actor_id = actor_id(this), dialog_id = d->dialog_id,
28897                                                        from_mentions](Result<Unit> result) {
28898                                  VLOG(notifications)
28899                                      << "Pending notifications timeout in " << dialog_id << " has expired";
28900                                  send_closure(actor_id, &MessagesManager::flush_pending_new_message_notifications,
28901                                               dialog_id, from_mentions, DialogId());
28902                                }))
28903           .release();
28904     }
28905     auto last_settings_dialog_id = (pending_notifications.empty() ? DialogId() : pending_notifications.back().first);
28906     pending_notifications.emplace_back((have_settings ? DialogId() : settings_dialog_id), m->message_id);
28907     if (!have_settings && last_settings_dialog_id != settings_dialog_id) {
28908       VLOG(notifications) << "Fetch notification settings for " << settings_dialog_id;
28909       auto promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_id = d->dialog_id, from_mentions,
28910                                              settings_dialog_id](Result<Unit> result) {
28911         send_closure(actor_id, &MessagesManager::flush_pending_new_message_notifications, dialog_id, from_mentions,
28912                      settings_dialog_id);
28913       });
28914       if (settings_dialog == nullptr && have_input_peer(settings_dialog_id, AccessRights::Read)) {
28915         force_create_dialog(settings_dialog_id, "add_new_message_notification 2");
28916         settings_dialog = get_dialog(settings_dialog_id);
28917       }
28918       if (settings_dialog != nullptr) {
28919         send_get_dialog_notification_settings_query(settings_dialog_id, std::move(promise));
28920       } else {
28921         send_get_dialog_query(settings_dialog_id, std::move(promise), 0, "add_new_message_notification");
28922       }
28923     }
28924     if (missing_pinned_message_id.is_valid()) {
28925       VLOG(notifications) << "Fetch pinned " << missing_pinned_message_id;
28926       auto promise = PromiseCreator::lambda(
28927           [actor_id = actor_id(this), dialog_id = d->dialog_id, from_mentions](Result<Unit> result) {
28928             send_closure(actor_id, &MessagesManager::flush_pending_new_message_notifications, dialog_id, from_mentions,
28929                          dialog_id);
28930           });
28931       get_message_from_server({d->dialog_id, missing_pinned_message_id}, std::move(promise),
28932                               "add_new_message_notification");
28933     }
28934     return false;
28935   }
28936 
28937   LOG_IF(WARNING, !have_settings) << "Have no notification settings for " << settings_dialog_id
28938                                   << ", but forced to send notification about " << m->message_id << " in "
28939                                   << d->dialog_id;
28940   auto &group_info = get_notification_group_info(d, m);
28941   auto notification_group_id = get_dialog_notification_group_id(d->dialog_id, group_info);
28942   if (!notification_group_id.is_valid()) {
28943     return false;
28944   }
28945   // if !force, then add_message_to_dialog will add the correspondence
28946   m->notification_id = get_next_notification_id(d, notification_group_id, force ? m->message_id : MessageId());
28947   if (!m->notification_id.is_valid()) {
28948     return false;
28949   }
28950   bool is_changed = set_dialog_last_notification(d->dialog_id, group_info, m->date, m->notification_id,
28951                                                  "add_new_message_notification 3");
28952   CHECK(is_changed);
28953   if (is_pinned) {
28954     set_dialog_pinned_message_notification(d, from_mentions ? m->message_id : MessageId(),
28955                                            "add_new_message_notification");
28956   }
28957   if (!m->notification_id.is_valid()) {
28958     // protection from accidental notification_id removal in set_dialog_pinned_message_notification
28959     return false;
28960   }
28961   VLOG(notifications) << "Create " << m->notification_id << " with " << m->message_id << " in " << group_info.group_id
28962                       << '/' << d->dialog_id;
28963   int32 min_delay_ms = 0;
28964   if (need_delay_message_content_notification(m->content.get(), td_->contacts_manager_->get_my_id())) {
28965     min_delay_ms = 3000;  // 3 seconds
28966   } else if (td_->is_online() && d->is_opened) {
28967     min_delay_ms = 1000;  // 1 second
28968   }
28969   bool is_silent = m->disable_notification || m->message_id <= d->max_notification_message_id;
28970   send_closure_later(G()->notification_manager(), &NotificationManager::add_notification, notification_group_id,
28971                      from_mentions ? NotificationGroupType::Mentions : NotificationGroupType::Messages, d->dialog_id,
28972                      m->date, settings_dialog_id, m->disable_notification, is_silent, min_delay_ms, m->notification_id,
28973                      create_new_message_notification(m->message_id), "add_new_message_notification");
28974   return true;
28975 }
28976 
flush_pending_new_message_notifications(DialogId dialog_id,bool from_mentions,DialogId settings_dialog_id)28977 void MessagesManager::flush_pending_new_message_notifications(DialogId dialog_id, bool from_mentions,
28978                                                               DialogId settings_dialog_id) {
28979   // flush pending notifications even while closing
28980 
28981   auto d = get_dialog(dialog_id);
28982   CHECK(d != nullptr);
28983   auto &pending_notifications =
28984       from_mentions ? d->pending_new_mention_notifications : d->pending_new_message_notifications;
28985   if (pending_notifications.empty()) {
28986     VLOG(notifications) << "Have no pending notifications in " << dialog_id << " to flush";
28987     return;
28988   }
28989   for (auto &it : pending_notifications) {
28990     if (it.first == settings_dialog_id || !settings_dialog_id.is_valid()) {
28991       it.first = DialogId();
28992     }
28993   }
28994 
28995   VLOG(notifications) << "Flush pending notifications in " << dialog_id
28996                       << " because of received notification settings in " << settings_dialog_id;
28997   auto it = pending_notifications.begin();
28998   while (it != pending_notifications.end() && it->first == DialogId()) {
28999     auto m = get_message(d, it->second);
29000     if (m != nullptr && add_new_message_notification(d, m, true)) {
29001       on_message_changed(d, m, false, "flush_pending_new_message_notifications");
29002     }
29003     ++it;
29004   }
29005 
29006   if (it == pending_notifications.end()) {
29007     reset_to_empty(pending_notifications);
29008   } else {
29009     pending_notifications.erase(pending_notifications.begin(), it);
29010   }
29011 }
29012 
remove_all_dialog_notifications(Dialog * d,bool from_mentions,const char * source)29013 void MessagesManager::remove_all_dialog_notifications(Dialog *d, bool from_mentions, const char *source) {
29014   // removes up to group_info.last_notification_id
29015   NotificationGroupInfo &group_info = from_mentions ? d->mention_notification_group : d->message_notification_group;
29016   if (group_info.group_id.is_valid() && group_info.last_notification_id.is_valid() &&
29017       group_info.max_removed_notification_id != group_info.last_notification_id) {
29018     VLOG(notifications) << "Set max_removed_notification_id in " << group_info.group_id << '/' << d->dialog_id << " to "
29019                         << group_info.last_notification_id << " from " << source;
29020     group_info.max_removed_notification_id = group_info.last_notification_id;
29021     if (d->max_notification_message_id > group_info.max_removed_message_id) {
29022       group_info.max_removed_message_id = d->max_notification_message_id.get_prev_server_message_id();
29023     }
29024     if (!d->pending_new_message_notifications.empty()) {
29025       for (auto &it : d->pending_new_message_notifications) {
29026         it.first = DialogId();
29027       }
29028       flush_pending_new_message_notifications(d->dialog_id, from_mentions, DialogId(UserId(static_cast<int64>(2))));
29029     }
29030     // remove_message_notifications will be called by NotificationManager
29031     send_closure_later(G()->notification_manager(), &NotificationManager::remove_notification_group,
29032                        group_info.group_id, group_info.last_notification_id, MessageId(), 0, true, Promise<Unit>());
29033     if (d->new_secret_chat_notification_id.is_valid() && &group_info == &d->message_notification_group) {
29034       remove_new_secret_chat_notification(d, false);
29035     } else {
29036       bool is_changed = set_dialog_last_notification(d->dialog_id, group_info, 0, NotificationId(), source);
29037       CHECK(is_changed);
29038     }
29039   }
29040 }
29041 
remove_message_dialog_notifications(Dialog * d,MessageId max_message_id,bool from_mentions,const char * source)29042 void MessagesManager::remove_message_dialog_notifications(Dialog *d, MessageId max_message_id, bool from_mentions,
29043                                                           const char *source) {
29044   // removes up to max_message_id
29045   CHECK(!max_message_id.is_scheduled());
29046   NotificationGroupInfo &group_info = from_mentions ? d->mention_notification_group : d->message_notification_group;
29047   if (!group_info.group_id.is_valid()) {
29048     return;
29049   }
29050 
29051   VLOG(notifications) << "Remove message dialog notifications in " << group_info.group_id << '/' << d->dialog_id
29052                       << " up to " << max_message_id << " from " << source;
29053 
29054   if (!d->pending_new_message_notifications.empty()) {
29055     for (auto &it : d->pending_new_message_notifications) {
29056       if (it.second <= max_message_id) {
29057         it.first = DialogId();
29058       }
29059     }
29060     flush_pending_new_message_notifications(d->dialog_id, from_mentions, DialogId(UserId(static_cast<int64>(3))));
29061   }
29062 
29063   auto max_notification_message_id = max_message_id;
29064   if (d->last_message_id.is_valid() && max_notification_message_id >= d->last_message_id) {
29065     max_notification_message_id = d->last_message_id;
29066     set_dialog_last_notification(d->dialog_id, group_info, 0, NotificationId(),
29067                                  "remove_message_dialog_notifications 1");
29068   } else if (max_notification_message_id == MessageId::max()) {
29069     max_notification_message_id = get_next_local_message_id(d);
29070     set_dialog_last_notification(d->dialog_id, group_info, 0, NotificationId(),
29071                                  "remove_message_dialog_notifications 2");
29072   } else {
29073     LOG(FATAL) << "TODO support notification deletion up to " << max_message_id << " if will be ever needed";
29074   }
29075 
29076   send_closure_later(G()->notification_manager(), &NotificationManager::remove_notification_group, group_info.group_id,
29077                      NotificationId(), max_notification_message_id, 0, true, Promise<Unit>());
29078 }
29079 
send_update_message_send_succeeded(Dialog * d,MessageId old_message_id,const Message * m) const29080 void MessagesManager::send_update_message_send_succeeded(Dialog *d, MessageId old_message_id, const Message *m) const {
29081   CHECK(m != nullptr);
29082   CHECK(d->is_update_new_chat_sent);
29083   if (!td_->auth_manager_->is_bot()) {
29084     d->yet_unsent_message_id_to_persistent_message_id.emplace(old_message_id, m->message_id);
29085   }
29086   send_closure(G()->td(), &Td::send_update,
29087                make_tl_object<td_api::updateMessageSendSucceeded>(
29088                    get_message_object(d->dialog_id, m, "send_update_message_send_succeeded"), old_message_id.get()));
29089 }
29090 
send_update_message_content(DialogId dialog_id,Message * m,bool is_message_in_dialog,const char * source)29091 void MessagesManager::send_update_message_content(DialogId dialog_id, Message *m, bool is_message_in_dialog,
29092                                                   const char *source) {
29093   Dialog *d = get_dialog(dialog_id);
29094   LOG_CHECK(d != nullptr) << "Send updateMessageContent in unknown " << dialog_id << " from " << source
29095                           << " with load count " << loaded_dialogs_.count(dialog_id);
29096   send_update_message_content(d, m, is_message_in_dialog, source);
29097 }
29098 
send_update_message_content(const Dialog * d,Message * m,bool is_message_in_dialog,const char * source)29099 void MessagesManager::send_update_message_content(const Dialog *d, Message *m, bool is_message_in_dialog,
29100                                                   const char *source) {
29101   CHECK(d != nullptr);
29102   CHECK(m != nullptr);
29103   if (is_message_in_dialog) {
29104     delete_bot_command_message_id(d->dialog_id, m->message_id);
29105     try_add_bot_command_message_id(d->dialog_id, m);
29106     reregister_message_reply(d, m);
29107     update_message_max_reply_media_timestamp(d, m, false);  // because the message reply can be just registered
29108     update_message_max_own_media_timestamp(d, m);
29109   }
29110   send_update_message_content_impl(d->dialog_id, m, source);
29111 }
29112 
send_update_message_content_impl(DialogId dialog_id,const Message * m,const char * source) const29113 void MessagesManager::send_update_message_content_impl(DialogId dialog_id, const Message *m, const char *source) const {
29114   CHECK(m != nullptr);
29115   if (!m->is_update_sent) {
29116     LOG(INFO) << "Skip updateMessageContent for " << m->message_id << " in " << dialog_id << " from " << source;
29117     return;
29118   }
29119   LOG(INFO) << "Send updateMessageContent for " << m->message_id << " in " << dialog_id << " from " << source;
29120   auto content_object = get_message_content_object(m->content.get(), td_, dialog_id, m->is_failed_to_send ? 0 : m->date,
29121                                                    m->is_content_secret, need_skip_bot_commands(dialog_id, m),
29122                                                    get_message_max_media_timestamp(m));
29123   send_closure(G()->td(), &Td::send_update,
29124                td_api::make_object<td_api::updateMessageContent>(dialog_id.get(), m->message_id.get(),
29125                                                                  std::move(content_object)));
29126 }
29127 
send_update_message_edited(DialogId dialog_id,const Message * m)29128 void MessagesManager::send_update_message_edited(DialogId dialog_id, const Message *m) {
29129   CHECK(m != nullptr);
29130   cancel_dialog_action(dialog_id, m);
29131   auto edit_date = m->hide_edit_date ? 0 : m->edit_date;
29132   send_closure(G()->td(), &Td::send_update,
29133                make_tl_object<td_api::updateMessageEdited>(dialog_id.get(), m->message_id.get(), edit_date,
29134                                                            get_reply_markup_object(m->reply_markup)));
29135 }
29136 
send_update_message_interaction_info(DialogId dialog_id,const Message * m) const29137 void MessagesManager::send_update_message_interaction_info(DialogId dialog_id, const Message *m) const {
29138   CHECK(m != nullptr);
29139   if (td_->auth_manager_->is_bot() || !m->is_update_sent) {
29140     return;
29141   }
29142 
29143   send_closure(G()->td(), &Td::send_update,
29144                make_tl_object<td_api::updateMessageInteractionInfo>(dialog_id.get(), m->message_id.get(),
29145                                                                     get_message_interaction_info_object(dialog_id, m)));
29146 }
29147 
send_update_message_live_location_viewed(FullMessageId full_message_id)29148 void MessagesManager::send_update_message_live_location_viewed(FullMessageId full_message_id) {
29149   CHECK(get_message(full_message_id) != nullptr);
29150   send_closure(G()->td(), &Td::send_update,
29151                td_api::make_object<td_api::updateMessageLiveLocationViewed>(full_message_id.get_dialog_id().get(),
29152                                                                             full_message_id.get_message_id().get()));
29153 }
29154 
send_update_delete_messages(DialogId dialog_id,vector<int64> && message_ids,bool is_permanent,bool from_cache) const29155 void MessagesManager::send_update_delete_messages(DialogId dialog_id, vector<int64> &&message_ids, bool is_permanent,
29156                                                   bool from_cache) const {
29157   if (message_ids.empty()) {
29158     return;
29159   }
29160 
29161   LOG_CHECK(have_dialog(dialog_id)) << "Wrong " << dialog_id << " in send_update_delete_messages";
29162   send_closure(
29163       G()->td(), &Td::send_update,
29164       make_tl_object<td_api::updateDeleteMessages>(dialog_id.get(), std::move(message_ids), is_permanent, from_cache));
29165 }
29166 
send_update_new_chat(Dialog * d)29167 void MessagesManager::send_update_new_chat(Dialog *d) {
29168   CHECK(d != nullptr);
29169   CHECK(d->messages == nullptr);
29170   auto chat_object = get_chat_object(d);
29171   bool has_action_bar = chat_object->action_bar_ != nullptr;
29172   bool has_theme = !chat_object->theme_name_.empty();
29173   d->last_sent_has_scheduled_messages = chat_object->has_scheduled_messages_;
29174   send_closure(G()->td(), &Td::send_update, make_tl_object<td_api::updateNewChat>(std::move(chat_object)));
29175   d->is_update_new_chat_sent = true;
29176 
29177   if (has_action_bar) {
29178     send_update_secret_chats_with_user_action_bar(d);
29179   }
29180   if (has_theme) {
29181     send_update_secret_chats_with_user_theme(d);
29182   }
29183 }
29184 
send_update_chat_draft_message(const Dialog * d)29185 void MessagesManager::send_update_chat_draft_message(const Dialog *d) {
29186   if (td_->auth_manager_->is_bot()) {
29187     // just in case
29188     return;
29189   }
29190 
29191   CHECK(d != nullptr);
29192   LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_draft_message";
29193   on_dialog_updated(d->dialog_id, "send_update_chat_draft_message");
29194   if (d->draft_message == nullptr || can_send_message(d->dialog_id).is_ok()) {
29195     send_closure(G()->td(), &Td::send_update,
29196                  make_tl_object<td_api::updateChatDraftMessage>(
29197                      d->dialog_id.get(), get_draft_message_object(d->draft_message), get_chat_positions_object(d)));
29198   }
29199 }
29200 
send_update_chat_last_message(Dialog * d,const char * source)29201 void MessagesManager::send_update_chat_last_message(Dialog *d, const char *source) {
29202   update_dialog_pos(d, source, false);
29203   send_update_chat_last_message_impl(d, source);
29204 }
29205 
send_update_chat_last_message_impl(const Dialog * d,const char * source) const29206 void MessagesManager::send_update_chat_last_message_impl(const Dialog *d, const char *source) const {
29207   if (td_->auth_manager_->is_bot()) {
29208     return;
29209   }
29210 
29211   CHECK(d != nullptr);
29212   LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_last_message from "
29213                                         << source;
29214   LOG(INFO) << "Send updateChatLastMessage in " << d->dialog_id << " to " << d->last_message_id << " from " << source;
29215   const auto *m = get_message(d, d->last_message_id);
29216   auto message_object = get_message_object(d->dialog_id, m, "send_update_chat_last_message_impl");
29217   auto positions_object = get_chat_positions_object(d);
29218   auto update = td_api::make_object<td_api::updateChatLastMessage>(d->dialog_id.get(), std::move(message_object),
29219                                                                    std::move(positions_object));
29220   send_closure(G()->td(), &Td::send_update, std::move(update));
29221 }
29222 
send_update_chat_filters()29223 void MessagesManager::send_update_chat_filters() {
29224   if (td_->auth_manager_->is_bot()) {
29225     return;
29226   }
29227 
29228   is_update_chat_filters_sent_ = true;
29229   send_closure(G()->td(), &Td::send_update, get_update_chat_filters_object());
29230 }
29231 
save_dialog_filters()29232 void MessagesManager::save_dialog_filters() {
29233   if (td_->auth_manager_->is_bot()) {
29234     return;
29235   }
29236 
29237   DialogFiltersLogEvent log_event;
29238   log_event.updated_date = dialog_filters_updated_date_;
29239   log_event.server_dialog_filters_in = &server_dialog_filters_;
29240   log_event.dialog_filters_in = &dialog_filters_;
29241 
29242   LOG(INFO) << "Save server chat filters " << get_dialog_filter_ids(server_dialog_filters_)
29243             << " and local chat filters " << get_dialog_filter_ids(dialog_filters_);
29244 
29245   G()->td_db()->get_binlog_pmc()->set("dialog_filters", log_event_store(log_event).as_slice().str());
29246 }
29247 
send_update_unread_message_count(DialogList & list,DialogId dialog_id,bool force,const char * source,bool from_database)29248 void MessagesManager::send_update_unread_message_count(DialogList &list, DialogId dialog_id, bool force,
29249                                                        const char *source, bool from_database) {
29250   if (td_->auth_manager_->is_bot() || !G()->parameters().use_message_db) {
29251     return;
29252   }
29253 
29254   auto dialog_list_id = list.dialog_list_id;
29255   CHECK(list.is_message_unread_count_inited_);
29256   if (list.unread_message_muted_count_ < 0 || list.unread_message_muted_count_ > list.unread_message_total_count_) {
29257     LOG(ERROR) << "Unread message count became invalid in " << dialog_list_id << ": "
29258                << list.unread_message_total_count_ << '/'
29259                << list.unread_message_total_count_ - list.unread_message_muted_count_ << " from " << source << " and "
29260                << dialog_id;
29261     if (list.unread_message_muted_count_ < 0) {
29262       list.unread_message_muted_count_ = 0;
29263     }
29264     if (list.unread_message_muted_count_ > list.unread_message_total_count_) {
29265       list.unread_message_total_count_ = list.unread_message_muted_count_;
29266     }
29267   }
29268 
29269   if (!from_database) {
29270     LOG(INFO) << "Save unread message count in " << dialog_list_id;
29271     G()->td_db()->get_binlog_pmc()->set(
29272         PSTRING() << "unread_message_count" << dialog_list_id.get(),
29273         PSTRING() << list.unread_message_total_count_ << ' ' << list.unread_message_muted_count_);
29274   }
29275 
29276   int32 unread_unmuted_count = list.unread_message_total_count_ - list.unread_message_muted_count_;
29277   if (!force && running_get_difference_) {
29278     LOG(INFO) << "Postpone updateUnreadMessageCount in " << dialog_list_id << " to " << list.unread_message_total_count_
29279               << '/' << unread_unmuted_count << " from " << source << " and " << dialog_id;
29280     postponed_unread_message_count_updates_.insert(dialog_list_id);
29281   } else {
29282     postponed_unread_message_count_updates_.erase(dialog_list_id);
29283     LOG(INFO) << "Send updateUnreadMessageCount in " << dialog_list_id << " to " << list.unread_message_total_count_
29284               << '/' << unread_unmuted_count << " from " << source << " and " << dialog_id;
29285     send_closure(G()->td(), &Td::send_update, get_update_unread_message_count_object(list));
29286   }
29287 }
29288 
send_update_unread_chat_count(DialogList & list,DialogId dialog_id,bool force,const char * source,bool from_database)29289 void MessagesManager::send_update_unread_chat_count(DialogList &list, DialogId dialog_id, bool force,
29290                                                     const char *source, bool from_database) {
29291   if (td_->auth_manager_->is_bot() || !G()->parameters().use_message_db) {
29292     return;
29293   }
29294 
29295   auto dialog_list_id = list.dialog_list_id;
29296   CHECK(list.is_dialog_unread_count_inited_);
29297   if (list.unread_dialog_muted_marked_count_ < 0 ||
29298       list.unread_dialog_marked_count_ < list.unread_dialog_muted_marked_count_ ||
29299       list.unread_dialog_muted_count_ < list.unread_dialog_muted_marked_count_ ||
29300       list.unread_dialog_total_count_ + list.unread_dialog_muted_marked_count_ <
29301           list.unread_dialog_muted_count_ + list.unread_dialog_marked_count_) {
29302     LOG(ERROR) << "Unread chat count became invalid in " << dialog_list_id << ": " << list.unread_dialog_total_count_
29303                << '/' << list.unread_dialog_total_count_ - list.unread_dialog_muted_count_ << '/'
29304                << list.unread_dialog_marked_count_ << '/'
29305                << list.unread_dialog_marked_count_ - list.unread_dialog_muted_marked_count_ << " from " << source
29306                << " and " << dialog_id;
29307     if (list.unread_dialog_muted_marked_count_ < 0) {
29308       list.unread_dialog_muted_marked_count_ = 0;
29309     }
29310     if (list.unread_dialog_marked_count_ < list.unread_dialog_muted_marked_count_) {
29311       list.unread_dialog_marked_count_ = list.unread_dialog_muted_marked_count_;
29312     }
29313     if (list.unread_dialog_muted_count_ < list.unread_dialog_muted_marked_count_) {
29314       list.unread_dialog_muted_count_ = list.unread_dialog_muted_marked_count_;
29315     }
29316     if (list.unread_dialog_total_count_ + list.unread_dialog_muted_marked_count_ <
29317         list.unread_dialog_muted_count_ + list.unread_dialog_marked_count_) {
29318       list.unread_dialog_total_count_ =
29319           list.unread_dialog_muted_count_ + list.unread_dialog_marked_count_ - list.unread_dialog_muted_marked_count_;
29320     }
29321   }
29322 
29323   if (!from_database) {
29324     save_unread_chat_count(list);
29325   }
29326 
29327   bool need_postpone = !force && running_get_difference_;
29328   int32 unread_unmuted_count = list.unread_dialog_total_count_ - list.unread_dialog_muted_count_;
29329   int32 unread_unmuted_marked_count = list.unread_dialog_marked_count_ - list.unread_dialog_muted_marked_count_;
29330   LOG(INFO) << (need_postpone ? "Postpone" : "Send") << " updateUnreadChatCount in " << dialog_list_id << " to "
29331             << list.in_memory_dialog_total_count_ << '/' << list.server_dialog_total_count_ << '+'
29332             << list.secret_chat_total_count_ << '/' << list.unread_dialog_total_count_ << '/' << unread_unmuted_count
29333             << '/' << list.unread_dialog_marked_count_ << '/' << unread_unmuted_marked_count << " from " << source
29334             << " and " << dialog_id;
29335   if (need_postpone) {
29336     postponed_unread_chat_count_updates_.insert(dialog_list_id);
29337   } else {
29338     postponed_unread_chat_count_updates_.erase(dialog_list_id);
29339     send_closure(G()->td(), &Td::send_update, get_update_unread_chat_count_object(list));
29340   }
29341 }
29342 
save_unread_chat_count(const DialogList & list)29343 void MessagesManager::save_unread_chat_count(const DialogList &list) {
29344   LOG(INFO) << "Save unread chat count in " << list.dialog_list_id;
29345   G()->td_db()->get_binlog_pmc()->set(
29346       PSTRING() << "unread_dialog_count" << list.dialog_list_id.get(),
29347       PSTRING() << list.unread_dialog_total_count_ << ' ' << list.unread_dialog_muted_count_ << ' '
29348                 << list.unread_dialog_marked_count_ << ' ' << list.unread_dialog_muted_marked_count_ << ' '
29349                 << list.server_dialog_total_count_ << ' ' << list.secret_chat_total_count_);
29350 }
29351 
send_update_chat_read_inbox(const Dialog * d,bool force,const char * source)29352 void MessagesManager::send_update_chat_read_inbox(const Dialog *d, bool force, const char *source) {
29353   if (td_->auth_manager_->is_bot()) {
29354     return;
29355   }
29356 
29357   CHECK(d != nullptr);
29358   LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_read_inbox from "
29359                                         << source;
29360   on_dialog_updated(d->dialog_id, source);
29361   if (!force && (running_get_difference_ || running_get_channel_difference(d->dialog_id) ||
29362                  get_channel_difference_to_log_event_id_.count(d->dialog_id) != 0)) {
29363     LOG(INFO) << "Postpone updateChatReadInbox in " << d->dialog_id << "(" << get_dialog_title(d->dialog_id) << ") to "
29364               << d->server_unread_count << " + " << d->local_unread_count << " from " << source;
29365     postponed_chat_read_inbox_updates_.insert(d->dialog_id);
29366   } else {
29367     postponed_chat_read_inbox_updates_.erase(d->dialog_id);
29368     LOG(INFO) << "Send updateChatReadInbox in " << d->dialog_id << "(" << get_dialog_title(d->dialog_id) << ") to "
29369               << d->server_unread_count << " + " << d->local_unread_count << " from " << source;
29370     send_closure(G()->td(), &Td::send_update,
29371                  make_tl_object<td_api::updateChatReadInbox>(d->dialog_id.get(), d->last_read_inbox_message_id.get(),
29372                                                              d->server_unread_count + d->local_unread_count));
29373   }
29374 }
29375 
send_update_chat_read_outbox(const Dialog * d)29376 void MessagesManager::send_update_chat_read_outbox(const Dialog *d) {
29377   if (td_->auth_manager_->is_bot()) {
29378     return;
29379   }
29380 
29381   CHECK(d != nullptr);
29382   LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_read_outbox";
29383   on_dialog_updated(d->dialog_id, "send_update_chat_read_outbox");
29384   send_closure(G()->td(), &Td::send_update,
29385                make_tl_object<td_api::updateChatReadOutbox>(d->dialog_id.get(), d->last_read_outbox_message_id.get()));
29386 }
29387 
send_update_chat_unread_mention_count(const Dialog * d)29388 void MessagesManager::send_update_chat_unread_mention_count(const Dialog *d) {
29389   if (td_->auth_manager_->is_bot()) {
29390     return;
29391   }
29392 
29393   CHECK(d != nullptr);
29394   LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_unread_mention_count";
29395   LOG(INFO) << "Update unread mention message count in " << d->dialog_id << " to " << d->unread_mention_count;
29396   on_dialog_updated(d->dialog_id, "send_update_chat_unread_mention_count");
29397   send_closure(G()->td(), &Td::send_update,
29398                make_tl_object<td_api::updateChatUnreadMentionCount>(d->dialog_id.get(), d->unread_mention_count));
29399 }
29400 
send_update_chat_position(DialogListId dialog_list_id,const Dialog * d,const char * source) const29401 void MessagesManager::send_update_chat_position(DialogListId dialog_list_id, const Dialog *d,
29402                                                 const char *source) const {
29403   if (td_->auth_manager_->is_bot()) {
29404     return;
29405   }
29406 
29407   CHECK(d != nullptr);
29408   LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_position";
29409   LOG(INFO) << "Send updateChatPosition for " << d->dialog_id << " in " << dialog_list_id << " from " << source;
29410   auto position = get_chat_position_object(dialog_list_id, d);
29411   if (position == nullptr) {
29412     position = td_api::make_object<td_api::chatPosition>(dialog_list_id.get_chat_list_object(), 0, false, nullptr);
29413   }
29414   send_closure(G()->td(), &Td::send_update,
29415                make_tl_object<td_api::updateChatPosition>(d->dialog_id.get(), std::move(position)));
29416 }
29417 
send_update_chat_online_member_count(DialogId dialog_id,int32 online_member_count) const29418 void MessagesManager::send_update_chat_online_member_count(DialogId dialog_id, int32 online_member_count) const {
29419   if (td_->auth_manager_->is_bot()) {
29420     return;
29421   }
29422 
29423   send_closure(G()->td(), &Td::send_update,
29424                make_tl_object<td_api::updateChatOnlineMemberCount>(dialog_id.get(), online_member_count));
29425 }
29426 
send_update_secret_chats_with_user_action_bar(const Dialog * d) const29427 void MessagesManager::send_update_secret_chats_with_user_action_bar(const Dialog *d) const {
29428   if (td_->auth_manager_->is_bot()) {
29429     return;
29430   }
29431 
29432   if (d->dialog_id.get_type() != DialogType::User) {
29433     return;
29434   }
29435 
29436   td_->contacts_manager_->for_each_secret_chat_with_user(
29437       d->dialog_id.get_user_id(), [this, user_d = d](SecretChatId secret_chat_id) {
29438         DialogId dialog_id(secret_chat_id);
29439         auto secret_chat_d = get_dialog(dialog_id);  // must not create the dialog
29440         if (secret_chat_d != nullptr && secret_chat_d->is_update_new_chat_sent) {
29441           send_closure(
29442               G()->td(), &Td::send_update,
29443               td_api::make_object<td_api::updateChatActionBar>(dialog_id.get(), get_chat_action_bar_object(user_d)));
29444         }
29445       });
29446 }
29447 
send_update_chat_action_bar(Dialog * d)29448 void MessagesManager::send_update_chat_action_bar(Dialog *d) {
29449   if (td_->auth_manager_->is_bot()) {
29450     return;
29451   }
29452   if (d->action_bar != nullptr && d->action_bar->is_empty()) {
29453     d->action_bar = nullptr;
29454   }
29455 
29456   CHECK(d != nullptr);
29457   LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_action_bar";
29458   on_dialog_updated(d->dialog_id, "send_update_chat_action_bar");
29459   send_closure(G()->td(), &Td::send_update,
29460                td_api::make_object<td_api::updateChatActionBar>(d->dialog_id.get(), get_chat_action_bar_object(d)));
29461 
29462   send_update_secret_chats_with_user_action_bar(d);
29463 }
29464 
send_update_secret_chats_with_user_theme(const Dialog * d) const29465 void MessagesManager::send_update_secret_chats_with_user_theme(const Dialog *d) const {
29466   if (td_->auth_manager_->is_bot()) {
29467     return;
29468   }
29469 
29470   if (d->dialog_id.get_type() != DialogType::User) {
29471     return;
29472   }
29473 
29474   td_->contacts_manager_->for_each_secret_chat_with_user(
29475       d->dialog_id.get_user_id(), [this, user_d = d](SecretChatId secret_chat_id) {
29476         DialogId dialog_id(secret_chat_id);
29477         auto secret_chat_d = get_dialog(dialog_id);  // must not create the dialog
29478         if (secret_chat_d != nullptr && secret_chat_d->is_update_new_chat_sent) {
29479           send_closure(G()->td(), &Td::send_update,
29480                        td_api::make_object<td_api::updateChatTheme>(dialog_id.get(), user_d->theme_name));
29481         }
29482       });
29483 }
29484 
send_update_chat_theme(const Dialog * d)29485 void MessagesManager::send_update_chat_theme(const Dialog *d) {
29486   if (td_->auth_manager_->is_bot()) {
29487     return;
29488   }
29489 
29490   CHECK(d != nullptr);
29491   CHECK(d->dialog_id.get_type() != DialogType::SecretChat);
29492   LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_theme";
29493   on_dialog_updated(d->dialog_id, "send_update_chat_theme");
29494   send_closure(G()->td(), &Td::send_update,
29495                td_api::make_object<td_api::updateChatTheme>(d->dialog_id.get(), d->theme_name));
29496 
29497   send_update_secret_chats_with_user_theme(d);
29498 }
29499 
send_update_chat_pending_join_requests(const Dialog * d)29500 void MessagesManager::send_update_chat_pending_join_requests(const Dialog *d) {
29501   if (td_->auth_manager_->is_bot()) {
29502     return;
29503   }
29504 
29505   CHECK(d != nullptr);
29506   LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_pending_join_requests";
29507   on_dialog_updated(d->dialog_id, "send_update_chat_pending_join_requests");
29508   send_closure(G()->td(), &Td::send_update,
29509                td_api::make_object<td_api::updateChatPendingJoinRequests>(d->dialog_id.get(),
29510                                                                           get_chat_join_requests_info_object(d)));
29511 }
29512 
send_update_chat_video_chat(const Dialog * d)29513 void MessagesManager::send_update_chat_video_chat(const Dialog *d) {
29514   CHECK(d != nullptr);
29515   LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_video_chat";
29516   on_dialog_updated(d->dialog_id, "send_update_chat_video_chat");
29517   send_closure(G()->td(), &Td::send_update,
29518                td_api::make_object<td_api::updateChatVideoChat>(d->dialog_id.get(), get_video_chat_object(d)));
29519 }
29520 
send_update_chat_default_message_sender_id(const Dialog * d)29521 void MessagesManager::send_update_chat_default_message_sender_id(const Dialog *d) {
29522   CHECK(!td_->auth_manager_->is_bot());
29523   CHECK(d != nullptr);
29524   LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_default_message_sender_id";
29525   on_dialog_updated(d->dialog_id, "send_update_chat_default_message_sender_id");
29526   send_closure(G()->td(), &Td::send_update,
29527                td_api::make_object<td_api::updateChatDefaultMessageSenderId>(d->dialog_id.get(),
29528                                                                              get_default_sender_id_object(d)));
29529 }
29530 
send_update_chat_message_ttl_setting(const Dialog * d)29531 void MessagesManager::send_update_chat_message_ttl_setting(const Dialog *d) {
29532   CHECK(d != nullptr);
29533   LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_message_ttl_setting";
29534   on_dialog_updated(d->dialog_id, "send_update_chat_message_ttl_setting");
29535   send_closure(G()->td(), &Td::send_update,
29536                td_api::make_object<td_api::updateChatMessageTtlSetting>(
29537                    d->dialog_id.get(), d->message_ttl_setting.get_message_ttl_setting_object()));
29538 }
29539 
send_update_chat_has_scheduled_messages(Dialog * d,bool from_deletion)29540 void MessagesManager::send_update_chat_has_scheduled_messages(Dialog *d, bool from_deletion) {
29541   if (td_->auth_manager_->is_bot()) {
29542     return;
29543   }
29544 
29545   if (d->scheduled_messages == nullptr) {
29546     if (d->has_scheduled_database_messages) {
29547       if (d->has_loaded_scheduled_messages_from_database) {
29548         set_dialog_has_scheduled_database_messages_impl(d, false);
29549       } else {
29550         CHECK(G()->parameters().use_message_db);
29551         repair_dialog_scheduled_messages(d);
29552       }
29553     }
29554     if (d->has_scheduled_server_messages) {
29555       if (from_deletion && d->scheduled_messages_sync_generation > 0) {
29556         set_dialog_has_scheduled_server_messages(d, false);
29557       } else {
29558         d->last_repair_scheduled_messages_generation = 0;
29559         repair_dialog_scheduled_messages(d);
29560       }
29561     }
29562   }
29563 
29564   LOG(INFO) << "In " << d->dialog_id << " have scheduled messages on server = " << d->has_scheduled_server_messages
29565             << ", in database = " << d->has_scheduled_database_messages
29566             << " and in memory = " << (d->scheduled_messages != nullptr)
29567             << "; was loaded from database = " << d->has_loaded_scheduled_messages_from_database;
29568   bool has_scheduled_messages = get_dialog_has_scheduled_messages(d);
29569   if (has_scheduled_messages == d->last_sent_has_scheduled_messages) {
29570     return;
29571   }
29572   d->last_sent_has_scheduled_messages = has_scheduled_messages;
29573 
29574   LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_has_scheduled_messages";
29575   send_closure(G()->td(), &Td::send_update,
29576                td_api::make_object<td_api::updateChatHasScheduledMessages>(d->dialog_id.get(), has_scheduled_messages));
29577 }
29578 
send_update_chat_action(DialogId dialog_id,MessageId top_thread_message_id,DialogId typing_dialog_id,const DialogAction & action)29579 void MessagesManager::send_update_chat_action(DialogId dialog_id, MessageId top_thread_message_id,
29580                                               DialogId typing_dialog_id, const DialogAction &action) {
29581   if (td_->auth_manager_->is_bot()) {
29582     return;
29583   }
29584 
29585   LOG(DEBUG) << "Send " << action << " of " << typing_dialog_id << " in thread of " << top_thread_message_id << " in "
29586              << dialog_id;
29587   send_closure(G()->td(), &Td::send_update,
29588                make_tl_object<td_api::updateChatAction>(
29589                    dialog_id.get(), top_thread_message_id.get(),
29590                    get_message_sender_object(td_, typing_dialog_id, "send_update_chat_action"),
29591                    action.get_chat_action_object()));
29592 }
29593 
on_send_message_get_quick_ack(int64 random_id)29594 void MessagesManager::on_send_message_get_quick_ack(int64 random_id) {
29595   auto it = being_sent_messages_.find(random_id);
29596   if (it == being_sent_messages_.end()) {
29597     LOG(ERROR) << "Receive quick ack about unknown message with random_id = " << random_id;
29598     return;
29599   }
29600 
29601   auto dialog_id = it->second.get_dialog_id();
29602   auto message_id = it->second.get_message_id();
29603 
29604   send_closure(G()->td(), &Td::send_update,
29605                make_tl_object<td_api::updateMessageSendAcknowledged>(dialog_id.get(), message_id.get()));
29606 }
29607 
check_send_message_result(int64 random_id,DialogId dialog_id,const telegram_api::Updates * updates_ptr,const char * source)29608 void MessagesManager::check_send_message_result(int64 random_id, DialogId dialog_id,
29609                                                 const telegram_api::Updates *updates_ptr, const char *source) {
29610   CHECK(updates_ptr != nullptr);
29611   CHECK(source != nullptr);
29612   auto sent_messages = UpdatesManager::get_new_messages(updates_ptr);
29613   auto sent_messages_random_ids = UpdatesManager::get_sent_messages_random_ids(updates_ptr);
29614   if (sent_messages.size() != 1u || sent_messages_random_ids.size() != 1u ||
29615       *sent_messages_random_ids.begin() != random_id || get_message_dialog_id(*sent_messages[0]) != dialog_id) {
29616     LOG(ERROR) << "Receive wrong result for sending message with random_id " << random_id << " from " << source
29617                << " to " << dialog_id << ": " << oneline(to_string(*updates_ptr));
29618     Dialog *d = get_dialog(dialog_id);
29619     CHECK(d != nullptr);
29620     if (dialog_id.get_type() == DialogType::Channel) {
29621       get_channel_difference(dialog_id, d->pts, true, "check_send_message_result");
29622     } else {
29623       td_->updates_manager_->schedule_get_difference("check_send_message_result");
29624     }
29625     repair_dialog_scheduled_messages(d);
29626   }
29627 }
29628 
on_send_message_success(int64 random_id,MessageId new_message_id,int32 date,int32 ttl_period,FileId new_file_id,const char * source)29629 FullMessageId MessagesManager::on_send_message_success(int64 random_id, MessageId new_message_id, int32 date,
29630                                                        int32 ttl_period, FileId new_file_id, const char *source) {
29631   CHECK(source != nullptr);
29632   // do not try to run getDifference from this function
29633   if (DROP_SEND_MESSAGE_UPDATES) {
29634     return {};
29635   }
29636   if (!new_message_id.is_valid()) {
29637     LOG(ERROR) << "Receive " << new_message_id << " as sent message from " << source;
29638     on_send_message_fail(
29639         random_id,
29640         Status::Error(500, "Internal Server Error: receive invalid message identifier as sent message identifier"));
29641     return {};
29642   }
29643   if (new_message_id.is_yet_unsent()) {
29644     LOG(ERROR) << "Receive " << new_message_id << " as sent message from " << source;
29645     on_send_message_fail(random_id,
29646                          Status::Error(500, "Internal Server Error: receive yet unsent message as sent message"));
29647     return {};
29648   }
29649 
29650   auto it = being_sent_messages_.find(random_id);
29651   if (it == being_sent_messages_.end()) {
29652     LOG(ERROR) << "Result from sendMessage for " << new_message_id << " with random_id " << random_id << " sent at "
29653                << date << " comes from " << source << " after updateNewMessageId, but was not discarded by pts";
29654     return {};
29655   }
29656 
29657   auto dialog_id = it->second.get_dialog_id();
29658   auto old_message_id = it->second.get_message_id();
29659 
29660   if (new_message_id.is_local() && dialog_id.get_type() != DialogType::SecretChat) {
29661     LOG(ERROR) << "Receive " << new_message_id << " as sent message from " << source;
29662     on_send_message_fail(random_id, Status::Error(500, "Internal Server Error: receive local as sent message"));
29663     return {};
29664   }
29665 
29666   being_sent_messages_.erase(it);
29667 
29668   Dialog *d = get_dialog(dialog_id);
29669   CHECK(d != nullptr);
29670 
29671   bool need_update_dialog_pos = false;
29672   being_readded_message_id_ = {dialog_id, old_message_id};
29673   unique_ptr<Message> sent_message = delete_message(d, old_message_id, false, &need_update_dialog_pos, source);
29674   if (sent_message == nullptr) {
29675     delete_sent_message_on_server(dialog_id, new_message_id);
29676     being_readded_message_id_ = FullMessageId();
29677     return {};
29678   }
29679 
29680   if (!have_input_peer(dialog_id, AccessRights::Read)) {
29681     // LOG(ERROR) << "Found " << old_message_id << " in inaccessible " << dialog_id;
29682     // dump_debug_message_op(d, 5);
29683   }
29684 
29685   // imitation of update_message(d, sent_message.get(), std::move(new_message), &need_update_dialog_pos, false);
29686   if (date <= 0) {
29687     LOG(ERROR) << "Receive " << new_message_id << " in " << dialog_id << " with wrong date " << date << " from "
29688                << source;
29689   } else {
29690     LOG_CHECK(sent_message->date > 0) << old_message_id << ' ' << sent_message->message_id << ' ' << new_message_id
29691                                       << ' ' << sent_message->date << ' ' << date << ' ' << source;
29692     sent_message->date = date;
29693     CHECK(d->last_message_id != old_message_id);
29694   }
29695 
29696   sent_message->ttl_period = ttl_period;
29697 
29698   // reply_to message may be already deleted
29699   // but can't use get_message_force for check, because the message can be already unloaded from the memory
29700   // if (get_message_force(d, sent_message->reply_to_message_id, "on_send_message_success 2") == nullptr) {
29701   //   sent_message->reply_to_message_id = MessageId();
29702   // }
29703 
29704   if (merge_message_content_file_id(td_, sent_message->content.get(), new_file_id)) {
29705     send_update_message_content(d, sent_message.get(), false, source);
29706   }
29707 
29708   if (old_message_id.is_valid() && new_message_id < old_message_id && !can_overflow_message_id(dialog_id)) {
29709     LOG(ERROR) << "Sent " << old_message_id << " to " << dialog_id << " as " << new_message_id;
29710   }
29711 
29712   set_message_id(sent_message, new_message_id);
29713 
29714   sent_message->from_database = false;
29715   sent_message->have_previous = true;
29716   sent_message->have_next = true;
29717 
29718   send_update_message_send_succeeded(d, old_message_id, sent_message.get());
29719 
29720   bool need_update = true;
29721   Message *m = add_message_to_dialog(d, std::move(sent_message), true, &need_update, &need_update_dialog_pos, source);
29722   if (need_update_dialog_pos) {
29723     send_update_chat_last_message(d, "on_send_message_success");
29724   }
29725 
29726   if (m == nullptr) {
29727     if (!(old_message_id.is_valid() && new_message_id < old_message_id) &&
29728         !(ttl_period > 0 && date + ttl_period <= G()->server_time())) {
29729       // if message ID has decreased, which could happen if some messages were lost,
29730       // or the message has already been deleted after TTL period, then the error is expected
29731       LOG(ERROR) << "Failed to add just sent " << old_message_id << " to " << dialog_id << " as " << new_message_id
29732                  << " from " << source << ": " << debug_add_message_to_dialog_fail_reason_;
29733     }
29734     send_update_delete_messages(dialog_id, {new_message_id.get()}, true, false);
29735     being_readded_message_id_ = FullMessageId();
29736     return {};
29737   }
29738 
29739   try_add_active_live_location(dialog_id, m);
29740   update_reply_count_by_message(d, +1, m);
29741   update_forward_count(dialog_id, m);
29742   being_readded_message_id_ = FullMessageId();
29743   return {dialog_id, new_message_id};
29744 }
29745 
on_send_message_file_part_missing(int64 random_id,int bad_part)29746 void MessagesManager::on_send_message_file_part_missing(int64 random_id, int bad_part) {
29747   auto it = being_sent_messages_.find(random_id);
29748   if (it == being_sent_messages_.end()) {
29749     // we can't receive fail more than once
29750     // but message can be successfully sent before
29751     LOG(WARNING) << "Receive FILE_PART_" << bad_part
29752                  << "_MISSING about successfully sent message with random_id = " << random_id;
29753     return;
29754   }
29755 
29756   auto full_message_id = it->second;
29757 
29758   being_sent_messages_.erase(it);
29759 
29760   Message *m = get_message(full_message_id);
29761   if (m == nullptr) {
29762     // message has already been deleted by the user or sent to inaccessible channel
29763     // don't need to send error to the user, because the message has already been deleted
29764     // and there is nothing to be deleted from the server
29765     LOG(INFO) << "Fail to send already deleted by the user or sent to inaccessible chat " << full_message_id;
29766     return;
29767   }
29768 
29769   auto dialog_id = full_message_id.get_dialog_id();
29770   if (!have_input_peer(dialog_id, AccessRights::Read)) {
29771     // LOG(ERROR) << "Found " << m->message_id << " in inaccessible " << dialog_id;
29772     // dump_debug_message_op(get_dialog(dialog_id), 5);
29773   }
29774 
29775   if (dialog_id.get_type() == DialogType::SecretChat) {
29776     CHECK(!m->message_id.is_scheduled());
29777     Dialog *d = get_dialog(dialog_id);
29778     CHECK(d != nullptr);
29779 
29780     // need to change message random_id before resending
29781     m->random_id = generate_new_random_id();
29782 
29783     delete_random_id_to_message_id_correspondence(d, random_id, m->message_id);
29784     add_random_id_to_message_id_correspondence(d, m->random_id, m->message_id);
29785 
29786     auto log_event = SendMessageLogEvent(dialog_id, m);
29787     CHECK(m->send_message_log_event_id != 0);
29788     binlog_rewrite(G()->td_db()->get_binlog(), m->send_message_log_event_id, LogEvent::HandlerType::SendMessage,
29789                    get_log_event_storer(log_event));
29790   }
29791 
29792   do_send_message(dialog_id, m, {bad_part});
29793 }
29794 
on_send_message_file_reference_error(int64 random_id)29795 void MessagesManager::on_send_message_file_reference_error(int64 random_id) {
29796   auto it = being_sent_messages_.find(random_id);
29797   if (it == being_sent_messages_.end()) {
29798     // we can't receive fail more than once
29799     // but message can be successfully sent before
29800     LOG(WARNING) << "Receive file reference invalid error about successfully sent message with random_id = "
29801                  << random_id;
29802     return;
29803   }
29804 
29805   auto full_message_id = it->second;
29806 
29807   being_sent_messages_.erase(it);
29808 
29809   Message *m = get_message(full_message_id);
29810   if (m == nullptr) {
29811     // message has already been deleted by the user or sent to inaccessible channel
29812     // don't need to send error to the user, because the message has already been deleted
29813     // and there is nothing to be deleted from the server
29814     LOG(INFO) << "Fail to send already deleted by the user or sent to inaccessible chat " << full_message_id;
29815     return;
29816   }
29817 
29818   auto dialog_id = full_message_id.get_dialog_id();
29819   if (!have_input_peer(dialog_id, AccessRights::Read)) {
29820     // LOG(ERROR) << "Found " << m->message_id << " in inaccessible " << dialog_id;
29821     // dump_debug_message_op(get_dialog(dialog_id), 5);
29822   }
29823 
29824   if (dialog_id.get_type() == DialogType::SecretChat) {
29825     CHECK(!m->message_id.is_scheduled());
29826     Dialog *d = get_dialog(dialog_id);
29827     CHECK(d != nullptr);
29828 
29829     // need to change message random_id before resending
29830     m->random_id = generate_new_random_id();
29831 
29832     delete_random_id_to_message_id_correspondence(d, random_id, m->message_id);
29833     add_random_id_to_message_id_correspondence(d, m->random_id, m->message_id);
29834 
29835     auto log_event = SendMessageLogEvent(dialog_id, m);
29836     CHECK(m->send_message_log_event_id != 0);
29837     binlog_rewrite(G()->td_db()->get_binlog(), m->send_message_log_event_id, LogEvent::HandlerType::SendMessage,
29838                    get_log_event_storer(log_event));
29839   }
29840 
29841   do_send_message(dialog_id, m, {-1});
29842 }
29843 
on_send_media_group_file_reference_error(DialogId dialog_id,vector<int64> random_ids)29844 void MessagesManager::on_send_media_group_file_reference_error(DialogId dialog_id, vector<int64> random_ids) {
29845   int64 media_album_id = 0;
29846   vector<MessageId> message_ids;
29847   vector<Message *> messages;
29848   for (auto &random_id : random_ids) {
29849     auto it = being_sent_messages_.find(random_id);
29850     if (it == being_sent_messages_.end()) {
29851       // we can't receive fail more than once
29852       // but message can be successfully sent before
29853       LOG(ERROR) << "Receive file reference invalid error about successfully sent message with random_id = "
29854                  << random_id;
29855       continue;
29856     }
29857 
29858     auto full_message_id = it->second;
29859 
29860     being_sent_messages_.erase(it);
29861 
29862     Message *m = get_message(full_message_id);
29863     if (m == nullptr) {
29864       // message has already been deleted by the user or sent to inaccessible channel
29865       // don't need to send error to the user, because the message has already been deleted
29866       // and there is nothing to be deleted from the server
29867       LOG(INFO) << "Fail to send already deleted by the user or sent to inaccessible chat " << full_message_id;
29868       continue;
29869     }
29870 
29871     CHECK(m->media_album_id != 0);
29872     CHECK(media_album_id == 0 || media_album_id == m->media_album_id);
29873     media_album_id = m->media_album_id;
29874 
29875     CHECK(dialog_id == full_message_id.get_dialog_id());
29876     message_ids.push_back(m->message_id);
29877     messages.push_back(m);
29878   }
29879 
29880   CHECK(dialog_id.get_type() != DialogType::SecretChat);
29881 
29882   if (message_ids.empty()) {
29883     // all messages was deleted, nothing to do
29884     return;
29885   }
29886 
29887   auto &request = pending_message_group_sends_[media_album_id];
29888   CHECK(!request.dialog_id.is_valid());
29889   CHECK(request.finished_count == 0);
29890   CHECK(request.results.empty());
29891   request.dialog_id = dialog_id;
29892   request.message_ids = std::move(message_ids);
29893   request.is_finished.resize(request.message_ids.size(), false);
29894   for (size_t i = 0; i < request.message_ids.size(); i++) {
29895     request.results.push_back(Status::OK());
29896   }
29897 
29898   for (auto m : messages) {
29899     do_send_message(dialog_id, m, {-1});
29900   }
29901 }
29902 
on_send_message_fail(int64 random_id,Status error)29903 void MessagesManager::on_send_message_fail(int64 random_id, Status error) {
29904   CHECK(error.is_error());
29905 
29906   auto it = being_sent_messages_.find(random_id);
29907   if (it == being_sent_messages_.end()) {
29908     // we can't receive fail more than once
29909     // but message can be successfully sent before
29910     if (error.code() != NetQuery::Canceled) {
29911       LOG(ERROR) << "Receive error " << error << " about successfully sent message with random_id = " << random_id;
29912     }
29913     return;
29914   }
29915 
29916   auto full_message_id = it->second;
29917 
29918   being_sent_messages_.erase(it);
29919 
29920   Message *m = get_message(full_message_id);
29921   if (m == nullptr) {
29922     // message has already been deleted by the user or sent to inaccessible channel
29923     // don't need to send error to the user, because the message has already been deleted
29924     // and there is nothing to be deleted from the server
29925     LOG(INFO) << "Fail to send already deleted by the user or sent to inaccessible chat " << full_message_id;
29926     return;
29927   }
29928   LOG_IF(ERROR, error.code() == NetQuery::Canceled)
29929       << "Receive error " << error << " about sent message with random_id = " << random_id;
29930 
29931   auto dialog_id = full_message_id.get_dialog_id();
29932   if (!have_input_peer(dialog_id, AccessRights::Read)) {
29933     // LOG(ERROR) << "Found " << m->message_id << " in inaccessible " << dialog_id;
29934     // dump_debug_message_op(get_dialog(dialog_id), 5);
29935   }
29936 
29937   int error_code = error.code();
29938   string error_message = error.message().str();
29939   switch (error_code) {
29940     case 420:
29941       error_code = 429;
29942       LOG(ERROR) << "Receive error 420: " << error_message;
29943       break;
29944     case 429:
29945       // nothing special, error description has already been changed
29946       LOG_IF(ERROR, !begins_with(error_message, "Too Many Requests: retry after "))
29947           << "Wrong error message: " << error_message;
29948       break;
29949     case 400:
29950       if (error.message() == "MESSAGE_TOO_LONG") {
29951         error_message = "Message is too long";
29952         // TODO move check to send_message
29953       } else if (error.message() == "INPUT_USER_DEACTIVATED") {
29954         error_code = 403;
29955         error_message = "User is deactivated";
29956       } else if (error.message() == "USER_IS_BLOCKED") {
29957         error_code = 403;
29958         if (td_->auth_manager_->is_bot()) {
29959           switch (dialog_id.get_type()) {
29960             case DialogType::User:
29961             case DialogType::SecretChat:
29962               error_message = "Bot was blocked by the user";
29963               break;
29964             case DialogType::Chat:
29965             case DialogType::Channel:
29966               error_message = "Bot was kicked from the chat";
29967               break;
29968             case DialogType::None:
29969             default:
29970               UNREACHABLE();
29971           }
29972         } else {
29973           switch (dialog_id.get_type()) {
29974             case DialogType::User:
29975             case DialogType::SecretChat:
29976               error_message = "User was blocked by the other user";
29977               break;
29978             case DialogType::Chat:
29979             case DialogType::Channel:
29980               error_message = "User is not in the chat";
29981               break;
29982             case DialogType::None:
29983             default:
29984               UNREACHABLE();
29985           }
29986         }
29987         // TODO add check to send_message
29988       } else if (error.message() == "USER_IS_BOT") {
29989         if (td_->auth_manager_->is_bot() &&
29990             (dialog_id.get_type() == DialogType::User || dialog_id.get_type() == DialogType::SecretChat)) {
29991           error_code = 403;
29992           if (td_->contacts_manager_->is_user_bot(dialog_id.get_user_id())) {
29993             error_message = "Bot can't send messages to bots";
29994           } else {
29995             error_message = "Bot can't send messages to the user";
29996           }
29997           // TODO move check to send_message
29998         }
29999       } else if (error.message() == "PEER_ID_INVALID") {
30000         error_code = 403;
30001         if (td_->auth_manager_->is_bot() &&
30002             (dialog_id.get_type() == DialogType::User || dialog_id.get_type() == DialogType::SecretChat)) {
30003           error_message = "Bot can't initiate conversation with a user";
30004         }
30005       } else if (error.message() == "WC_CONVERT_URL_INVALID" || error.message() == "EXTERNAL_URL_INVALID") {
30006         error_message = "Wrong HTTP URL specified";
30007       } else if (error.message() == "WEBPAGE_CURL_FAILED") {
30008         error_message = "Failed to get HTTP URL content";
30009       } else if (error.message() == "WEBPAGE_MEDIA_EMPTY") {
30010         error_message = "Wrong type of the web page content";
30011       } else if (error.message() == "MEDIA_EMPTY") {
30012         auto content_type = m->content->get_type();
30013         if (content_type == MessageContentType::Game) {
30014           error_message = "Wrong game short name specified";
30015         } else if (content_type == MessageContentType::Invoice) {
30016           error_message = "Wrong invoice information specified";
30017         } else if (content_type == MessageContentType::Poll) {
30018           error_message = "Wrong poll data specified";
30019         } else if (content_type == MessageContentType::Contact) {
30020           error_message = "Wrong phone number specified";
30021         } else {
30022           error_message = "Wrong file identifier/HTTP URL specified";
30023         }
30024       } else if (error.message() == "PHOTO_EXT_INVALID") {
30025         error_message = "Photo has unsupported extension. Use one of .jpg, .jpeg, .gif, .png, .tif or .bmp";
30026       }
30027       break;
30028     case 403:
30029       if (error.message() == "MESSAGE_DELETE_FORBIDDEN") {
30030         error_code = 400;
30031         error_message = "Message can't be deleted";
30032       } else if (error.message() != "CHANNEL_PUBLIC_GROUP_NA" && error.message() != "USER_IS_BLOCKED" &&
30033                  error.message() != "USER_BOT_INVALID" && error.message() != "USER_DELETED") {
30034         error_code = 400;
30035       }
30036       break;
30037     // TODO other codes
30038     default:
30039       break;
30040   }
30041   if (error.message() == "REPLY_MARKUP_INVALID") {
30042     if (m->reply_markup == nullptr) {
30043       LOG(ERROR) << "Receive " << error.message() << " for "
30044                  << oneline(to_string(get_message_object(dialog_id, m, "on_send_message_fail")));
30045     } else {
30046       LOG(ERROR) << "Receive " << error.message() << " for " << full_message_id << " with keyboard "
30047                  << *m->reply_markup;
30048     }
30049   }
30050   LOG_IF(WARNING, error_code != 403) << "Fail to send " << full_message_id << " with the error " << error;
30051   if (error_code <= 0) {
30052     error_code = 500;
30053   }
30054   fail_send_message(full_message_id, error_code, error_message);
30055 }
30056 
get_next_message_id(Dialog * d,MessageType type)30057 MessageId MessagesManager::get_next_message_id(Dialog *d, MessageType type) {
30058   CHECK(d != nullptr);
30059   MessageId last_message_id =
30060       std::max({d->last_message_id, d->last_new_message_id, d->last_database_message_id, d->last_assigned_message_id,
30061                 d->last_clear_history_message_id, d->deleted_last_message_id, d->max_unavailable_message_id,
30062                 d->max_added_message_id});
30063   if (last_message_id < d->last_read_inbox_message_id &&
30064       d->last_read_inbox_message_id < d->last_new_message_id.get_next_server_message_id()) {
30065     last_message_id = d->last_read_inbox_message_id;
30066   }
30067   if (last_message_id < d->last_read_outbox_message_id &&
30068       d->last_read_outbox_message_id < d->last_new_message_id.get_next_server_message_id()) {
30069     last_message_id = d->last_read_outbox_message_id;
30070   }
30071 
30072   d->last_assigned_message_id = last_message_id.get_next_message_id(type);
30073   if (d->last_assigned_message_id > MessageId::max()) {
30074     LOG(FATAL) << "Force restart because of message_id overflow: " << d->last_assigned_message_id;
30075   }
30076   CHECK(d->last_assigned_message_id.is_valid());
30077   return d->last_assigned_message_id;
30078 }
30079 
get_next_yet_unsent_message_id(Dialog * d)30080 MessageId MessagesManager::get_next_yet_unsent_message_id(Dialog *d) {
30081   return get_next_message_id(d, MessageType::YetUnsent);
30082 }
30083 
get_next_local_message_id(Dialog * d)30084 MessageId MessagesManager::get_next_local_message_id(Dialog *d) {
30085   return get_next_message_id(d, MessageType::Local);
30086 }
30087 
get_next_yet_unsent_scheduled_message_id(Dialog * d,int32 date)30088 MessageId MessagesManager::get_next_yet_unsent_scheduled_message_id(Dialog *d, int32 date) {
30089   CHECK(date > 0);
30090 
30091   MessageId message_id(ScheduledServerMessageId(1), date);
30092 
30093   auto it = MessagesConstIterator(d, MessageId(ScheduledServerMessageId(), date + 1, true));
30094   if (*it != nullptr && (*it)->message_id > message_id) {
30095     message_id = (*it)->message_id;
30096   }
30097 
30098   auto &last_assigned_message_id = d->last_assigned_scheduled_message_id[date];
30099   if (last_assigned_message_id != MessageId() && last_assigned_message_id > message_id) {
30100     message_id = last_assigned_message_id;
30101   }
30102 
30103   last_assigned_message_id = message_id.get_next_message_id(MessageType::YetUnsent);
30104   return last_assigned_message_id;
30105 }
30106 
fail_send_message(FullMessageId full_message_id,int error_code,const string & error_message)30107 void MessagesManager::fail_send_message(FullMessageId full_message_id, int error_code, const string &error_message) {
30108   auto dialog_id = full_message_id.get_dialog_id();
30109   Dialog *d = get_dialog(dialog_id);
30110   CHECK(d != nullptr);
30111   MessageId old_message_id = full_message_id.get_message_id();
30112   CHECK(old_message_id.is_valid() || old_message_id.is_valid_scheduled());
30113   CHECK(old_message_id.is_yet_unsent());
30114 
30115   bool need_update_dialog_pos = false;
30116   being_readded_message_id_ = full_message_id;
30117   unique_ptr<Message> message = delete_message(d, old_message_id, false, &need_update_dialog_pos, "fail send message");
30118   if (message == nullptr) {
30119     // message has already been deleted by the user or sent to inaccessible channel
30120     // don't need to send update to the user, because the message has already been deleted
30121     // and there is nothing to be deleted from the server
30122     being_readded_message_id_ = FullMessageId();
30123     return;
30124   }
30125 
30126   if (!have_input_peer(dialog_id, AccessRights::Read)) {
30127     // LOG(ERROR) << "Found " << old_message_id << " in inaccessible " << dialog_id;
30128     // dump_debug_message_op(d, 5);
30129   }
30130 
30131   MessageId new_message_id =
30132       old_message_id.get_next_message_id(MessageType::Local);  // trying to not change message place
30133   if (!old_message_id.is_scheduled()) {
30134     if (get_message_force(d, new_message_id, "fail_send_message") != nullptr ||
30135         d->deleted_message_ids.count(new_message_id) || new_message_id <= d->last_clear_history_message_id) {
30136       new_message_id = get_next_local_message_id(d);
30137     } else if (new_message_id > d->last_assigned_message_id) {
30138       d->last_assigned_message_id = new_message_id;
30139     }
30140   } else {
30141     // check deleted_message_ids, because the new_message_id is not a server scheduled
30142     while (get_message_force(d, new_message_id, "fail_send_message") != nullptr ||
30143            d->deleted_message_ids.count(new_message_id)) {
30144       new_message_id = new_message_id.get_next_message_id(MessageType::Local);
30145     }
30146   }
30147 
30148   set_message_id(message, new_message_id);
30149   if (old_message_id.is_scheduled()) {
30150     CHECK(message->message_id.is_valid_scheduled());
30151   } else {
30152     CHECK(message->message_id.is_valid());
30153   }
30154   if (message->forward_info == nullptr && message->view_count == 1) {
30155     message->view_count = 0;
30156   }
30157   message->is_failed_to_send = true;
30158   message->send_error_code = error_code;
30159   message->send_error_message = error_message;
30160   message->try_resend_at = 0.0;
30161   Slice retry_after_prefix("Too Many Requests: retry after ");
30162   if (error_code == 429 && begins_with(error_message, retry_after_prefix)) {
30163     auto r_retry_after = to_integer_safe<int32>(error_message.substr(retry_after_prefix.size()));
30164     if (r_retry_after.is_ok() && r_retry_after.ok() > 0) {
30165       message->try_resend_at = Time::now() + r_retry_after.ok();
30166     }
30167   }
30168   update_failed_to_send_message_content(td_, message->content);
30169 
30170   message->from_database = false;
30171   message->have_previous = true;
30172   message->have_next = true;
30173 
30174   bool need_update = false;
30175   Message *m = add_message_to_dialog(dialog_id, std::move(message), false, &need_update, &need_update_dialog_pos,
30176                                      "fail_send_message");
30177   LOG_CHECK(m != nullptr) << "Failed to add failed to send " << new_message_id << " to " << dialog_id << " due to "
30178                           << debug_add_message_to_dialog_fail_reason_;
30179   if (!m->message_id.is_scheduled()) {
30180     // add_message_to_dialog will not update counts, because need_update == false
30181     update_message_count_by_index(d, +1, m);
30182     update_reply_count_by_message(d, +1, m);  // no-op because the message isn't server
30183   }
30184   register_new_local_message_id(d, m);
30185 
30186   LOG(INFO) << "Send updateMessageSendFailed for " << full_message_id;
30187   if (!td_->auth_manager_->is_bot()) {
30188     d->yet_unsent_message_id_to_persistent_message_id.emplace(old_message_id, m->message_id);
30189   }
30190   send_closure(G()->td(), &Td::send_update,
30191                make_tl_object<td_api::updateMessageSendFailed>(get_message_object(dialog_id, m, "fail_send_message"),
30192                                                                old_message_id.get(), error_code, error_message));
30193   if (need_update_dialog_pos) {
30194     send_update_chat_last_message(d, "fail_send_message");
30195   }
30196   being_readded_message_id_ = FullMessageId();
30197 }
30198 
fail_send_message(FullMessageId full_message_id,Status error)30199 void MessagesManager::fail_send_message(FullMessageId full_message_id, Status error) {
30200   fail_send_message(full_message_id, error.code(), error.message().str());
30201 }
30202 
fail_edit_message_media(FullMessageId full_message_id,Status && error)30203 void MessagesManager::fail_edit_message_media(FullMessageId full_message_id, Status &&error) {
30204   auto dialog_id = full_message_id.get_dialog_id();
30205   Dialog *d = get_dialog(dialog_id);
30206   CHECK(d != nullptr);
30207   MessageId message_id = full_message_id.get_message_id();
30208   CHECK(message_id.is_any_server());
30209 
30210   auto m = get_message(d, message_id);
30211   if (m == nullptr) {
30212     // message has already been deleted by the user or sent to inaccessible channel
30213     return;
30214   }
30215   CHECK(m->edited_content != nullptr);
30216   m->edit_promise.set_error(std::move(error));
30217   cancel_edit_message_media(dialog_id, m, "Failed to edit message. MUST BE IGNORED");
30218 }
30219 
on_update_dialog_draft_message(DialogId dialog_id,tl_object_ptr<telegram_api::DraftMessage> && draft_message)30220 void MessagesManager::on_update_dialog_draft_message(DialogId dialog_id,
30221                                                      tl_object_ptr<telegram_api::DraftMessage> &&draft_message) {
30222   if (!dialog_id.is_valid()) {
30223     LOG(ERROR) << "Receive update chat draft in invalid " << dialog_id;
30224     return;
30225   }
30226   auto d = get_dialog_force(dialog_id, "on_update_dialog_draft_message");
30227   if (d == nullptr) {
30228     LOG(INFO) << "Ignore update chat draft in unknown " << dialog_id;
30229     if (!have_input_peer(dialog_id, AccessRights::Read)) {
30230       LOG(ERROR) << "Have no read access to " << dialog_id << " to repair chat draft message";
30231     } else {
30232       send_get_dialog_query(dialog_id, Auto(), 0, "on_update_dialog_draft_message");
30233     }
30234     return;
30235   }
30236   update_dialog_draft_message(d, get_draft_message(td_->contacts_manager_.get(), std::move(draft_message)), true, true);
30237 }
30238 
update_dialog_draft_message(Dialog * d,unique_ptr<DraftMessage> && draft_message,bool from_update,bool need_update_dialog_pos)30239 bool MessagesManager::update_dialog_draft_message(Dialog *d, unique_ptr<DraftMessage> &&draft_message, bool from_update,
30240                                                   bool need_update_dialog_pos) {
30241   CHECK(d != nullptr);
30242   if (from_update && d->is_opened && d->draft_message != nullptr) {
30243     // send the update anyway, despite it shouldn't be applied client-side
30244     // return false;
30245   }
30246   if (draft_message == nullptr) {
30247     if (d->draft_message != nullptr) {
30248       d->draft_message = nullptr;
30249       if (need_update_dialog_pos) {
30250         update_dialog_pos(d, "update_dialog_draft_message", false);
30251       }
30252       send_update_chat_draft_message(d);
30253       return true;
30254     }
30255   } else {
30256     if (d->draft_message != nullptr && d->draft_message->reply_to_message_id == draft_message->reply_to_message_id &&
30257         d->draft_message->input_message_text == draft_message->input_message_text) {
30258       if (d->draft_message->date < draft_message->date) {
30259         d->draft_message->date = draft_message->date;
30260         if (need_update_dialog_pos) {
30261           update_dialog_pos(d, "update_dialog_draft_message 2", false);
30262         }
30263         send_update_chat_draft_message(d);
30264         return true;
30265       }
30266     } else {
30267       if (!from_update || d->draft_message == nullptr || d->draft_message->date <= draft_message->date) {
30268         d->draft_message = std::move(draft_message);
30269         if (need_update_dialog_pos) {
30270           update_dialog_pos(d, "update_dialog_draft_message 3", false);
30271         }
30272         send_update_chat_draft_message(d);
30273         return true;
30274       }
30275     }
30276   }
30277   return false;
30278 }
30279 
on_update_dialog_is_pinned(FolderId folder_id,DialogId dialog_id,bool is_pinned)30280 void MessagesManager::on_update_dialog_is_pinned(FolderId folder_id, DialogId dialog_id, bool is_pinned) {
30281   if (td_->auth_manager_->is_bot()) {
30282     // just in case
30283     return;
30284   }
30285 
30286   if (!dialog_id.is_valid()) {
30287     LOG(ERROR) << "Receive pin of invalid " << dialog_id;
30288     return;
30289   }
30290 
30291   auto d = get_dialog_force(dialog_id, "on_update_dialog_is_pinned");
30292   if (d == nullptr) {
30293     LOG(INFO) << "Can't apply updateDialogPinned in " << folder_id << " with unknown " << dialog_id;
30294     on_update_pinned_dialogs(folder_id);
30295     return;
30296   }
30297   if (d->order == DEFAULT_ORDER) {
30298     // the chat can't be pinned or is already unpinned
30299     // don't change it's folder_id
30300     LOG(INFO) << "Can't apply updateDialogPinned in " << folder_id << " with " << dialog_id;
30301     return;
30302   }
30303 
30304   auto *list = get_dialog_list(DialogListId(folder_id));
30305   CHECK(list != nullptr);
30306   if (!list->are_pinned_dialogs_inited_) {
30307     return;
30308   }
30309 
30310   set_dialog_folder_id(d, folder_id);
30311   set_dialog_is_pinned(DialogListId(folder_id), d, is_pinned);
30312 }
30313 
on_update_pinned_dialogs(FolderId folder_id)30314 void MessagesManager::on_update_pinned_dialogs(FolderId folder_id) {
30315   if (td_->auth_manager_->is_bot()) {
30316     // just in case
30317     return;
30318   }
30319 
30320   // TODO log event + delete_log_event_promise
30321 
30322   auto *list = get_dialog_list(DialogListId(folder_id));
30323   if (list == nullptr || !list->are_pinned_dialogs_inited_) {
30324     return;
30325   }
30326   // preload all pinned dialogs
30327   int32 limit = narrow_cast<int32>(list->pinned_dialogs_.size()) +
30328                 (folder_id == FolderId::main() && sponsored_dialog_id_.is_valid() ? 1 : 0);
30329   get_dialogs_from_list(DialogListId(folder_id), limit, Auto());
30330   reload_pinned_dialogs(DialogListId(folder_id), Auto());
30331 }
30332 
on_update_dialog_is_marked_as_unread(DialogId dialog_id,bool is_marked_as_unread)30333 void MessagesManager::on_update_dialog_is_marked_as_unread(DialogId dialog_id, bool is_marked_as_unread) {
30334   if (td_->auth_manager_->is_bot()) {
30335     // just in case
30336     return;
30337   }
30338 
30339   if (!dialog_id.is_valid()) {
30340     LOG(ERROR) << "Receive marking as unread of invalid " << dialog_id;
30341     return;
30342   }
30343 
30344   auto d = get_dialog_force(dialog_id, "on_update_dialog_is_marked_as_unread");
30345   if (d == nullptr) {
30346     // nothing to do
30347     return;
30348   }
30349 
30350   if (is_marked_as_unread == d->is_marked_as_unread) {
30351     return;
30352   }
30353 
30354   set_dialog_is_marked_as_unread(d, is_marked_as_unread);
30355 }
30356 
set_dialog_is_marked_as_unread(Dialog * d,bool is_marked_as_unread)30357 void MessagesManager::set_dialog_is_marked_as_unread(Dialog *d, bool is_marked_as_unread) {
30358   if (td_->auth_manager_->is_bot()) {
30359     // just in case
30360     return;
30361   }
30362 
30363   CHECK(d != nullptr);
30364   CHECK(d->is_marked_as_unread != is_marked_as_unread);
30365   d->is_marked_as_unread = is_marked_as_unread;
30366   on_dialog_updated(d->dialog_id, "set_dialog_is_marked_as_unread");
30367 
30368   LOG(INFO) << "Set " << d->dialog_id << " is marked as unread to " << is_marked_as_unread;
30369   LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in set_dialog_is_marked_as_unread";
30370   send_closure(G()->td(), &Td::send_update,
30371                make_tl_object<td_api::updateChatIsMarkedAsUnread>(d->dialog_id.get(), is_marked_as_unread));
30372 
30373   if (d->server_unread_count + d->local_unread_count == 0 && need_unread_counter(d->order)) {
30374     int32 delta = d->is_marked_as_unread ? 1 : -1;
30375     for (auto &list : get_dialog_lists(d)) {
30376       if (list.is_dialog_unread_count_inited_) {
30377         list.unread_dialog_total_count_ += delta;
30378         list.unread_dialog_marked_count_ += delta;
30379         if (is_dialog_muted(d)) {
30380           list.unread_dialog_muted_count_ += delta;
30381           list.unread_dialog_muted_marked_count_ += delta;
30382         }
30383         send_update_unread_chat_count(list, d->dialog_id, true, "set_dialog_is_marked_as_unread");
30384       }
30385     }
30386 
30387     if (!dialog_filters_.empty()) {
30388       update_dialog_lists(d, get_dialog_positions(d), true, false, "set_dialog_is_marked_as_unread");
30389     }
30390   }
30391 }
30392 
on_update_dialog_is_blocked(DialogId dialog_id,bool is_blocked)30393 void MessagesManager::on_update_dialog_is_blocked(DialogId dialog_id, bool is_blocked) {
30394   if (!dialog_id.is_valid()) {
30395     LOG(ERROR) << "Receive pinned message in invalid " << dialog_id;
30396     return;
30397   }
30398   if (dialog_id.get_type() == DialogType::User) {
30399     td_->contacts_manager_->on_update_user_is_blocked(dialog_id.get_user_id(), is_blocked);
30400   }
30401 
30402   auto d = get_dialog_force(dialog_id, "on_update_dialog_is_blocked");
30403   if (d == nullptr) {
30404     // nothing to do
30405     return;
30406   }
30407 
30408   if (d->is_blocked == is_blocked) {
30409     if (!d->is_is_blocked_inited) {
30410       CHECK(is_blocked == false);
30411       d->is_is_blocked_inited = true;
30412       on_dialog_updated(dialog_id, "on_update_dialog_is_blocked");
30413     }
30414     return;
30415   }
30416 
30417   set_dialog_is_blocked(d, is_blocked);
30418 }
30419 
set_dialog_is_blocked(Dialog * d,bool is_blocked)30420 void MessagesManager::set_dialog_is_blocked(Dialog *d, bool is_blocked) {
30421   CHECK(d != nullptr);
30422   CHECK(d->is_blocked != is_blocked);
30423   d->is_blocked = is_blocked;
30424   d->is_is_blocked_inited = true;
30425   on_dialog_updated(d->dialog_id, "set_dialog_is_blocked");
30426 
30427   LOG(INFO) << "Set " << d->dialog_id << " is_blocked to " << is_blocked;
30428   LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in set_dialog_is_blocked";
30429   send_closure(G()->td(), &Td::send_update,
30430                make_tl_object<td_api::updateChatIsBlocked>(d->dialog_id.get(), is_blocked));
30431 
30432   if (d->dialog_id.get_type() == DialogType::User) {
30433     td_->contacts_manager_->on_update_user_is_blocked(d->dialog_id.get_user_id(), is_blocked);
30434 
30435     if (d->know_action_bar) {
30436       if (is_blocked) {
30437         if (d->action_bar != nullptr) {
30438           d->action_bar = nullptr;
30439           send_update_chat_action_bar(d);
30440         }
30441       } else {
30442         repair_dialog_action_bar(d, "on_dialog_user_is_blocked_updated");
30443       }
30444     }
30445 
30446     td_->contacts_manager_->for_each_secret_chat_with_user(
30447         d->dialog_id.get_user_id(), [this, is_blocked](SecretChatId secret_chat_id) {
30448           DialogId dialog_id(secret_chat_id);
30449           auto d = get_dialog(dialog_id);  // must not create the dialog
30450           if (d != nullptr && d->is_update_new_chat_sent && d->is_blocked != is_blocked) {
30451             set_dialog_is_blocked(d, is_blocked);
30452           }
30453         });
30454   }
30455 }
30456 
on_update_dialog_last_pinned_message_id(DialogId dialog_id,MessageId pinned_message_id)30457 void MessagesManager::on_update_dialog_last_pinned_message_id(DialogId dialog_id, MessageId pinned_message_id) {
30458   if (!dialog_id.is_valid()) {
30459     LOG(ERROR) << "Receive pinned message in invalid " << dialog_id;
30460     return;
30461   }
30462   if (!pinned_message_id.is_valid() && pinned_message_id != MessageId()) {
30463     LOG(ERROR) << "Receive as pinned message " << pinned_message_id;
30464     return;
30465   }
30466 
30467   auto d = get_dialog_force(dialog_id, "on_update_dialog_last_pinned_message_id");
30468   if (d == nullptr) {
30469     // nothing to do
30470     return;
30471   }
30472 
30473   set_dialog_last_pinned_message_id(d, pinned_message_id);
30474 }
30475 
set_dialog_last_pinned_message_id(Dialog * d,MessageId pinned_message_id)30476 void MessagesManager::set_dialog_last_pinned_message_id(Dialog *d, MessageId pinned_message_id) {
30477   CHECK(d != nullptr);
30478   Message *m = get_message_force(d, pinned_message_id, "set_dialog_last_pinned_message_id");
30479   if (m != nullptr && update_message_is_pinned(d, m, true, "set_dialog_last_pinned_message_id")) {
30480     on_message_changed(d, m, true, "set_dialog_last_pinned_message_id");
30481   }
30482 
30483   if (d->is_last_pinned_message_id_inited && d->last_pinned_message_id == pinned_message_id) {
30484     return;
30485   }
30486   d->last_pinned_message_id = pinned_message_id;
30487   d->is_last_pinned_message_id_inited = true;
30488   on_dialog_updated(d->dialog_id, "set_dialog_last_pinned_message_id");
30489 
30490   LOG(INFO) << "Set " << d->dialog_id << " pinned message to " << pinned_message_id;
30491 }
30492 
drop_dialog_last_pinned_message_id(Dialog * d)30493 void MessagesManager::drop_dialog_last_pinned_message_id(Dialog *d) {
30494   d->last_pinned_message_id = MessageId();
30495   d->is_last_pinned_message_id_inited = false;
30496   on_dialog_updated(d->dialog_id, "drop_dialog_last_pinned_message_id");
30497 
30498   LOG(INFO) << "Drop " << d->dialog_id << " pinned message";
30499 
30500   create_actor<SleepActor>(
30501       "ReloadDialogFullInfoActor", 1.0,
30502       PromiseCreator::lambda([actor_id = actor_id(this), dialog_id = d->dialog_id](Result<Unit> result) {
30503         send_closure(actor_id, &MessagesManager::reload_dialog_info_full, dialog_id);
30504       }))
30505       .release();
30506 }
30507 
on_update_dialog_theme_name(DialogId dialog_id,string theme_name)30508 void MessagesManager::on_update_dialog_theme_name(DialogId dialog_id, string theme_name) {
30509   if (!dialog_id.is_valid()) {
30510     LOG(ERROR) << "Receive theme in invalid " << dialog_id;
30511     return;
30512   }
30513   if (td_->auth_manager_->is_bot()) {
30514     return;
30515   }
30516 
30517   auto d = get_dialog_force(dialog_id, "on_update_dialog_theme_name");
30518   if (d == nullptr) {
30519     // nothing to do
30520     return;
30521   }
30522 
30523   set_dialog_theme_name(d, std::move(theme_name));
30524 }
30525 
set_dialog_theme_name(Dialog * d,string theme_name)30526 void MessagesManager::set_dialog_theme_name(Dialog *d, string theme_name) {
30527   CHECK(d != nullptr);
30528   if (td_->auth_manager_->is_bot()) {
30529     return;
30530   }
30531 
30532   bool is_changed = d->theme_name != theme_name;
30533   if (!is_changed && d->is_theme_name_inited) {
30534     return;
30535   }
30536   d->theme_name = std::move(theme_name);
30537   d->is_theme_name_inited = true;
30538 
30539   if (is_changed) {
30540     LOG(INFO) << "Set " << d->dialog_id << " theme to \"" << d->theme_name << '"';
30541     send_update_chat_theme(d);
30542   } else {
30543     on_dialog_updated(d->dialog_id, "set_dialog_theme_name");
30544   }
30545 }
30546 
drop_dialog_pending_join_requests(DialogId dialog_id)30547 void MessagesManager::drop_dialog_pending_join_requests(DialogId dialog_id) {
30548   CHECK(dialog_id.is_valid());
30549   if (td_->auth_manager_->is_bot()) {
30550     return;
30551   }
30552   auto d = get_dialog(dialog_id);  // called from update_chat/channel, must not create the dialog
30553   if (d != nullptr && d->is_update_new_chat_sent) {
30554     set_dialog_pending_join_requests(d, 0, {});
30555   }
30556 }
30557 
on_update_dialog_pending_join_requests(DialogId dialog_id,int32 pending_join_request_count,vector<int64> pending_requesters)30558 void MessagesManager::on_update_dialog_pending_join_requests(DialogId dialog_id, int32 pending_join_request_count,
30559                                                              vector<int64> pending_requesters) {
30560   if (!dialog_id.is_valid()) {
30561     LOG(ERROR) << "Receive pending join request count in invalid " << dialog_id;
30562     return;
30563   }
30564   if (td_->auth_manager_->is_bot()) {
30565     return;
30566   }
30567 
30568   auto d = get_dialog_force(dialog_id, "on_update_dialog_pending_join_request_count");
30569   if (d == nullptr) {
30570     // nothing to do
30571     return;
30572   }
30573 
30574   auto pending_join_request_user_ids = UserId::get_user_ids(pending_requesters);
30575   td::remove_if(pending_join_request_user_ids, [](UserId user_id) { return !user_id.is_valid(); });
30576   set_dialog_pending_join_requests(d, pending_join_request_count, std::move(pending_join_request_user_ids));
30577 }
30578 
fix_pending_join_requests(DialogId dialog_id,int32 & pending_join_request_count,vector<UserId> & pending_join_request_user_ids) const30579 void MessagesManager::fix_pending_join_requests(DialogId dialog_id, int32 &pending_join_request_count,
30580                                                 vector<UserId> &pending_join_request_user_ids) const {
30581   bool need_drop_pending_join_requests = [&] {
30582     if (pending_join_request_count < 0) {
30583       return true;
30584     }
30585     switch (dialog_id.get_type()) {
30586       case DialogType::User:
30587       case DialogType::SecretChat:
30588         return true;
30589       case DialogType::Chat: {
30590         auto chat_id = dialog_id.get_chat_id();
30591         auto status = td_->contacts_manager_->get_chat_status(chat_id);
30592         if (!status.can_manage_invite_links()) {
30593           return true;
30594         }
30595         break;
30596       }
30597       case DialogType::Channel: {
30598         auto channel_id = dialog_id.get_channel_id();
30599         auto status = td_->contacts_manager_->get_channel_permissions(channel_id);
30600         if (!status.can_manage_invite_links()) {
30601           return true;
30602         }
30603         break;
30604       }
30605       case DialogType::None:
30606       default:
30607         UNREACHABLE();
30608     }
30609     return false;
30610   }();
30611   if (need_drop_pending_join_requests) {
30612     pending_join_request_count = 0;
30613     pending_join_request_user_ids.clear();
30614   } else if (static_cast<size_t>(pending_join_request_count) < pending_join_request_user_ids.size()) {
30615     LOG(ERROR) << "Fix pending join request count from " << pending_join_request_count << " to "
30616                << pending_join_request_user_ids.size();
30617     pending_join_request_count = narrow_cast<int32>(pending_join_request_user_ids.size());
30618   }
30619 }
30620 
set_dialog_pending_join_requests(Dialog * d,int32 pending_join_request_count,vector<UserId> pending_join_request_user_ids)30621 void MessagesManager::set_dialog_pending_join_requests(Dialog *d, int32 pending_join_request_count,
30622                                                        vector<UserId> pending_join_request_user_ids) {
30623   if (td_->auth_manager_->is_bot()) {
30624     return;
30625   }
30626 
30627   CHECK(d != nullptr);
30628   fix_pending_join_requests(d->dialog_id, pending_join_request_count, pending_join_request_user_ids);
30629   if (d->pending_join_request_count == pending_join_request_count &&
30630       d->pending_join_request_user_ids == pending_join_request_user_ids) {
30631     return;
30632   }
30633   d->pending_join_request_count = pending_join_request_count;
30634   d->pending_join_request_user_ids = std::move(pending_join_request_user_ids);
30635   send_update_chat_pending_join_requests(d);
30636 }
30637 
repair_dialog_scheduled_messages(Dialog * d)30638 void MessagesManager::repair_dialog_scheduled_messages(Dialog *d) {
30639   if (td_->auth_manager_->is_bot() || d->dialog_id.get_type() == DialogType::SecretChat) {
30640     return;
30641   }
30642 
30643   if (d->last_repair_scheduled_messages_generation == scheduled_messages_sync_generation_) {
30644     return;
30645   }
30646   d->last_repair_scheduled_messages_generation = scheduled_messages_sync_generation_;
30647 
30648   // TODO create log event
30649   auto dialog_id = d->dialog_id;
30650   LOG(INFO) << "Repair scheduled messages in " << dialog_id << " with generation "
30651             << d->last_repair_scheduled_messages_generation;
30652   get_dialog_scheduled_messages(dialog_id, false, true,
30653                                 PromiseCreator::lambda([actor_id = actor_id(this), dialog_id](Unit) {
30654                                   send_closure(G()->messages_manager(), &MessagesManager::get_dialog_scheduled_messages,
30655                                                dialog_id, true, true, Promise<Unit>());
30656                                 }));
30657 }
30658 
on_update_dialog_has_scheduled_server_messages(DialogId dialog_id,bool has_scheduled_server_messages)30659 void MessagesManager::on_update_dialog_has_scheduled_server_messages(DialogId dialog_id,
30660                                                                      bool has_scheduled_server_messages) {
30661   CHECK(dialog_id.is_valid());
30662   if (td_->auth_manager_->is_bot() || dialog_id.get_type() == DialogType::SecretChat) {
30663     return;
30664   }
30665 
30666   auto d = get_dialog_force(dialog_id, "on_update_dialog_has_scheduled_server_messages");
30667   if (d == nullptr) {
30668     // nothing to do
30669     return;
30670   }
30671 
30672   LOG(INFO) << "Receive has_scheduled_server_messages = " << has_scheduled_server_messages << " in " << dialog_id;
30673   if (d->has_scheduled_server_messages != has_scheduled_server_messages) {
30674     set_dialog_has_scheduled_server_messages(d, has_scheduled_server_messages);
30675   } else if (has_scheduled_server_messages !=
30676              (d->has_scheduled_database_messages || d->scheduled_messages != nullptr)) {
30677     repair_dialog_scheduled_messages(d);
30678   }
30679 }
30680 
set_dialog_has_scheduled_server_messages(Dialog * d,bool has_scheduled_server_messages)30681 void MessagesManager::set_dialog_has_scheduled_server_messages(Dialog *d, bool has_scheduled_server_messages) {
30682   CHECK(d != nullptr);
30683   CHECK(d->has_scheduled_server_messages != has_scheduled_server_messages);
30684   d->has_scheduled_server_messages = has_scheduled_server_messages;
30685   repair_dialog_scheduled_messages(d);
30686   on_dialog_updated(d->dialog_id, "set_dialog_has_scheduled_server_messages");
30687 
30688   LOG(INFO) << "Set " << d->dialog_id << " has_scheduled_server_messages to " << has_scheduled_server_messages;
30689 
30690   send_update_chat_has_scheduled_messages(d, false);
30691 }
30692 
set_dialog_has_scheduled_database_messages(DialogId dialog_id,bool has_scheduled_database_messages)30693 void MessagesManager::set_dialog_has_scheduled_database_messages(DialogId dialog_id,
30694                                                                  bool has_scheduled_database_messages) {
30695   if (G()->close_flag()) {
30696     return;
30697   }
30698   return set_dialog_has_scheduled_database_messages_impl(get_dialog(dialog_id), has_scheduled_database_messages);
30699 }
30700 
set_dialog_has_scheduled_database_messages_impl(Dialog * d,bool has_scheduled_database_messages)30701 void MessagesManager::set_dialog_has_scheduled_database_messages_impl(Dialog *d, bool has_scheduled_database_messages) {
30702   CHECK(d != nullptr);
30703   if (d->has_scheduled_database_messages == has_scheduled_database_messages) {
30704     return;
30705   }
30706 
30707   if (d->has_scheduled_database_messages && d->scheduled_messages != nullptr &&
30708       !d->scheduled_messages->message_id.is_yet_unsent()) {
30709     // to prevent race between add_message_to_database and check of has_scheduled_database_messages
30710     return;
30711   }
30712 
30713   CHECK(G()->parameters().use_message_db);
30714 
30715   d->has_scheduled_database_messages = has_scheduled_database_messages;
30716   on_dialog_updated(d->dialog_id, "set_dialog_has_scheduled_database_messages");
30717 }
30718 
on_update_dialog_folder_id(DialogId dialog_id,FolderId folder_id)30719 void MessagesManager::on_update_dialog_folder_id(DialogId dialog_id, FolderId folder_id) {
30720   auto d = get_dialog_force(dialog_id, "on_update_dialog_folder_id");
30721   if (d == nullptr) {
30722     // nothing to do
30723     return;
30724   }
30725 
30726   set_dialog_folder_id(d, folder_id);
30727 }
30728 
set_dialog_folder_id(Dialog * d,FolderId folder_id)30729 void MessagesManager::set_dialog_folder_id(Dialog *d, FolderId folder_id) {
30730   if (td_->auth_manager_->is_bot()) {
30731     return;
30732   }
30733 
30734   CHECK(d != nullptr);
30735 
30736   if (d->folder_id == folder_id) {
30737     if (!d->is_folder_id_inited) {
30738       LOG(INFO) << "Folder of " << d->dialog_id << " is still " << folder_id;
30739       do_set_dialog_folder_id(d, folder_id);
30740     }
30741     return;
30742   }
30743 
30744   LOG(INFO) << "Change " << d->dialog_id << " folder from " << d->folder_id << " to " << folder_id;
30745 
30746   auto dialog_positions = get_dialog_positions(d);
30747 
30748   if (get_dialog_pinned_order(DialogListId(d->folder_id), d->dialog_id) != DEFAULT_ORDER) {
30749     set_dialog_is_pinned(DialogListId(d->folder_id), d, false, false);
30750   }
30751 
30752   DialogDate dialog_date(d->order, d->dialog_id);
30753   if (get_dialog_folder(d->folder_id)->ordered_dialogs_.erase(dialog_date) == 0) {
30754     LOG_IF(ERROR, d->order != DEFAULT_ORDER) << d->dialog_id << " not found in the chat list";
30755   }
30756 
30757   do_set_dialog_folder_id(d, folder_id);
30758 
30759   get_dialog_folder(d->folder_id)->ordered_dialogs_.insert(dialog_date);
30760 
30761   update_dialog_lists(d, std::move(dialog_positions), true, false, "set_dialog_folder_id");
30762 }
30763 
do_set_dialog_folder_id(Dialog * d,FolderId folder_id)30764 void MessagesManager::do_set_dialog_folder_id(Dialog *d, FolderId folder_id) {
30765   CHECK(!td_->auth_manager_->is_bot());
30766   if (d->folder_id == folder_id && d->is_folder_id_inited) {
30767     return;
30768   }
30769 
30770   d->folder_id = folder_id;
30771   d->is_folder_id_inited = true;
30772 
30773   if (d->dialog_id.get_type() == DialogType::SecretChat) {
30774     // need to change action bar only for the secret chat and keep unarchive for the main chat
30775     auto user_id = td_->contacts_manager_->get_secret_chat_user_id(d->dialog_id.get_secret_chat_id());
30776     if (d->is_update_new_chat_sent && user_id.is_valid()) {
30777       const Dialog *user_d = get_dialog(DialogId(user_id));
30778       if (user_d != nullptr && user_d->action_bar != nullptr && user_d->action_bar->can_unarchive()) {
30779         send_closure(
30780             G()->td(), &Td::send_update,
30781             td_api::make_object<td_api::updateChatActionBar>(d->dialog_id.get(), get_chat_action_bar_object(d)));
30782       }
30783     }
30784   } else if (folder_id != FolderId::archive() && d->action_bar != nullptr && d->action_bar->on_dialog_unarchived()) {
30785     send_update_chat_action_bar(d);
30786   }
30787 
30788   on_dialog_updated(d->dialog_id, "do_set_dialog_folder_id");
30789 }
30790 
on_update_dialog_group_call(DialogId dialog_id,bool has_active_group_call,bool is_group_call_empty,const char * source,bool force)30791 void MessagesManager::on_update_dialog_group_call(DialogId dialog_id, bool has_active_group_call,
30792                                                   bool is_group_call_empty, const char *source, bool force) {
30793   LOG(INFO) << "Update voice chat in " << dialog_id << " with has_active_voice_chat = " << has_active_group_call
30794             << " and is_voice_chat_empty = " << is_group_call_empty << " from " << source;
30795   CHECK(dialog_id.is_valid());
30796   Dialog *d = get_dialog(dialog_id);  // must not create the Dialog, because it is called from on_get_chat
30797   if (d == nullptr) {
30798     LOG(INFO) << "Can't find " << dialog_id;
30799     pending_dialog_group_call_updates_[dialog_id] = {has_active_group_call, is_group_call_empty};
30800     return;
30801   }
30802 
30803   if (!has_active_group_call) {
30804     is_group_call_empty = false;
30805   }
30806   if (d->active_group_call_id.is_valid() && has_active_group_call && is_group_call_empty &&
30807       (td_->group_call_manager_->is_group_call_being_joined(d->active_group_call_id) ||
30808        td_->group_call_manager_->is_group_call_joined(d->active_group_call_id))) {
30809     LOG(INFO) << "Fix is_group_call_empty to false";
30810     is_group_call_empty = false;
30811   }
30812   if (d->has_active_group_call == has_active_group_call && d->is_group_call_empty == is_group_call_empty) {
30813     return;
30814   }
30815   if (!force && d->active_group_call_id.is_valid() && has_active_group_call &&
30816       td_->group_call_manager_->is_group_call_being_joined(d->active_group_call_id)) {
30817     LOG(INFO) << "Ignore update in a being joined group call";
30818     return;
30819   }
30820 
30821   if (d->has_active_group_call && !has_active_group_call && d->active_group_call_id.is_valid()) {
30822     d->active_group_call_id = InputGroupCallId();
30823     d->has_active_group_call = false;
30824     d->is_group_call_empty = false;
30825     send_update_chat_video_chat(d);
30826   } else if (d->has_active_group_call && has_active_group_call) {
30827     d->is_group_call_empty = is_group_call_empty;
30828     send_update_chat_video_chat(d);
30829   } else {
30830     d->has_active_group_call = has_active_group_call;
30831     d->is_group_call_empty = is_group_call_empty;
30832     on_dialog_updated(dialog_id, "on_update_dialog_group_call");
30833 
30834     if (has_active_group_call && !d->active_group_call_id.is_valid() && !td_->auth_manager_->is_bot()) {
30835       repair_dialog_active_group_call_id(dialog_id);
30836     }
30837   }
30838 }
30839 
on_update_dialog_group_call_id(DialogId dialog_id,InputGroupCallId input_group_call_id)30840 void MessagesManager::on_update_dialog_group_call_id(DialogId dialog_id, InputGroupCallId input_group_call_id) {
30841   auto d = get_dialog_force(dialog_id, "on_update_dialog_group_call_id");
30842   if (d == nullptr) {
30843     // nothing to do
30844     return;
30845   }
30846 
30847   if (d->active_group_call_id != input_group_call_id) {
30848     LOG(INFO) << "Update active group call in " << dialog_id << " to " << input_group_call_id;
30849     d->active_group_call_id = input_group_call_id;
30850     bool has_active_group_call = input_group_call_id.is_valid();
30851     if (has_active_group_call != d->has_active_group_call) {
30852       d->has_active_group_call = has_active_group_call;
30853       if (!has_active_group_call) {
30854         d->is_group_call_empty = false;
30855       }
30856     }
30857     send_update_chat_video_chat(d);
30858   }
30859 }
30860 
on_update_dialog_default_join_group_call_as_dialog_id(DialogId dialog_id,DialogId default_join_as_dialog_id,bool force)30861 void MessagesManager::on_update_dialog_default_join_group_call_as_dialog_id(DialogId dialog_id,
30862                                                                             DialogId default_join_as_dialog_id,
30863                                                                             bool force) {
30864   auto d = get_dialog_force(dialog_id, "on_update_dialog_default_join_group_call_as_dialog_id");
30865   if (d == nullptr) {
30866     // nothing to do
30867     return;
30868   }
30869 
30870   if (!force && d->active_group_call_id.is_valid() &&
30871       td_->group_call_manager_->is_group_call_being_joined(d->active_group_call_id)) {
30872     LOG(INFO) << "Ignore default_join_as_dialog_id update in a being joined group call";
30873     return;
30874   }
30875 
30876   if (default_join_as_dialog_id.is_valid()) {
30877     if (default_join_as_dialog_id.get_type() != DialogType::User) {
30878       force_create_dialog(default_join_as_dialog_id, "on_update_dialog_default_join_group_call_as_dialog_id");
30879     } else if (!td_->contacts_manager_->have_user_force(default_join_as_dialog_id.get_user_id()) ||
30880                default_join_as_dialog_id != get_my_dialog_id()) {
30881       default_join_as_dialog_id = DialogId();
30882     }
30883   }
30884 
30885   if (d->default_join_group_call_as_dialog_id != default_join_as_dialog_id) {
30886     d->default_join_group_call_as_dialog_id = default_join_as_dialog_id;
30887     send_update_chat_video_chat(d);
30888   }
30889 }
30890 
on_update_dialog_default_send_message_as_dialog_id(DialogId dialog_id,DialogId default_send_as_dialog_id,bool force)30891 void MessagesManager::on_update_dialog_default_send_message_as_dialog_id(DialogId dialog_id,
30892                                                                          DialogId default_send_as_dialog_id,
30893                                                                          bool force) {
30894   if (td_->auth_manager_->is_bot()) {
30895     // just in case
30896     return;
30897   }
30898   auto dialog_type = dialog_id.get_type();
30899   if (dialog_type != DialogType::Channel || is_broadcast_channel(dialog_id)) {
30900     if (default_send_as_dialog_id != DialogId()) {
30901       LOG(ERROR) << "Receive default sender " << default_send_as_dialog_id << " in " << dialog_id;
30902     }
30903     return;
30904   }
30905 
30906   auto d = get_dialog_force(dialog_id, "on_update_dialog_default_send_message_as_dialog_id");
30907   if (d == nullptr) {
30908     // nothing to do
30909     return;
30910   }
30911 
30912   if (!force) {
30913     // TODO ignore update if have being sent messages
30914   }
30915 
30916   if (default_send_as_dialog_id.is_valid()) {
30917     if (default_send_as_dialog_id.get_type() != DialogType::User) {
30918       force_create_dialog(default_send_as_dialog_id, "on_update_dialog_default_send_message_as_dialog_id");
30919     } else if (!td_->contacts_manager_->have_user_force(default_send_as_dialog_id.get_user_id()) ||
30920                default_send_as_dialog_id != get_my_dialog_id()) {
30921       default_send_as_dialog_id = DialogId();
30922     }
30923   }
30924 
30925   if (d->default_send_message_as_dialog_id != default_send_as_dialog_id) {
30926     LOG(INFO) << "Set default message sender in " << dialog_id << " to " << default_send_as_dialog_id;
30927     d->default_send_message_as_dialog_id = default_send_as_dialog_id;
30928     send_update_chat_default_message_sender_id(d);
30929   }
30930 }
30931 
on_update_dialog_message_ttl_setting(DialogId dialog_id,MessageTtlSetting message_ttl_setting)30932 void MessagesManager::on_update_dialog_message_ttl_setting(DialogId dialog_id, MessageTtlSetting message_ttl_setting) {
30933   auto d = get_dialog_force(dialog_id, "on_update_dialog_message_ttl_setting");
30934   if (d == nullptr) {
30935     // nothing to do
30936     return;
30937   }
30938 
30939   if (d->message_ttl_setting != message_ttl_setting) {
30940     d->message_ttl_setting = message_ttl_setting;
30941     d->is_message_ttl_setting_inited = true;
30942     send_update_chat_message_ttl_setting(d);
30943   }
30944   if (!d->is_message_ttl_setting_inited) {
30945     d->is_message_ttl_setting_inited = true;
30946     on_dialog_updated(dialog_id, "on_update_dialog_message_ttl_setting");
30947   }
30948 }
30949 
on_update_dialog_filters()30950 void MessagesManager::on_update_dialog_filters() {
30951   if (td_->auth_manager_->is_bot()) {
30952     // just in case
30953     return;
30954   }
30955 
30956   schedule_dialog_filters_reload(0.0);
30957 }
30958 
on_create_new_dialog_success(int64 random_id,tl_object_ptr<telegram_api::Updates> && updates,DialogType expected_type,Promise<Unit> && promise)30959 void MessagesManager::on_create_new_dialog_success(int64 random_id, tl_object_ptr<telegram_api::Updates> &&updates,
30960                                                    DialogType expected_type, Promise<Unit> &&promise) {
30961   auto sent_messages = UpdatesManager::get_new_messages(updates.get());
30962   auto sent_messages_random_ids = UpdatesManager::get_sent_messages_random_ids(updates.get());
30963   if (sent_messages.size() != 1u || sent_messages_random_ids.size() != 1u) {
30964     LOG(ERROR) << "Receive wrong result for create group or channel chat " << oneline(to_string(updates));
30965     return on_create_new_dialog_fail(random_id, Status::Error(500, "Unsupported server response"), std::move(promise));
30966   }
30967 
30968   auto message = *sent_messages.begin();
30969   // int64 message_random_id = *sent_messages_random_ids.begin();
30970   // TODO check that message_random_id equals random_id after messages_createChat will be updated
30971 
30972   auto dialog_id = get_message_dialog_id(*message);
30973   if (dialog_id.get_type() != expected_type) {
30974     return on_create_new_dialog_fail(random_id, Status::Error(500, "Chat of wrong type has been created"),
30975                                      std::move(promise));
30976   }
30977 
30978   auto it = created_dialogs_.find(random_id);
30979   CHECK(it != created_dialogs_.end());
30980   CHECK(it->second == DialogId());
30981 
30982   it->second = dialog_id;
30983 
30984   const Dialog *d = get_dialog(dialog_id);
30985   if (d != nullptr && d->last_new_message_id.is_valid()) {
30986     // dialog have been already created and at least one non-temporary message was added,
30987     // i.e. we are not interested in the creation of dialog by searchMessages
30988     // then messages have already been added, so just set promise
30989     return promise.set_value(Unit());
30990   }
30991 
30992   if (pending_created_dialogs_.find(dialog_id) == pending_created_dialogs_.end()) {
30993     pending_created_dialogs_.emplace(dialog_id, std::move(promise));
30994   } else {
30995     LOG(ERROR) << dialog_id << " returned twice as result of chat creation";
30996     return on_create_new_dialog_fail(random_id, Status::Error(500, "Chat was created earlier"), std::move(promise));
30997   }
30998 
30999   td_->updates_manager_->on_get_updates(std::move(updates), Promise<Unit>());
31000 }
31001 
on_create_new_dialog_fail(int64 random_id,Status error,Promise<Unit> && promise)31002 void MessagesManager::on_create_new_dialog_fail(int64 random_id, Status error, Promise<Unit> &&promise) {
31003   LOG(INFO) << "Clean up creation of group or channel chat";
31004   auto it = created_dialogs_.find(random_id);
31005   CHECK(it != created_dialogs_.end());
31006   CHECK(it->second == DialogId());
31007   created_dialogs_.erase(it);
31008 
31009   CHECK(error.is_error());
31010   promise.set_error(std::move(error));
31011 
31012   // repairing state by running get difference
31013   td_->updates_manager_->get_difference("on_create_new_dialog_fail");
31014 }
31015 
on_dialog_bots_updated(DialogId dialog_id,vector<UserId> bot_user_ids,bool from_database)31016 void MessagesManager::on_dialog_bots_updated(DialogId dialog_id, vector<UserId> bot_user_ids, bool from_database) {
31017   if (td_->auth_manager_->is_bot()) {
31018     return;
31019   }
31020 
31021   auto d = from_database ? get_dialog(dialog_id) : get_dialog_force(dialog_id, "on_dialog_bots_updated");
31022   if (d == nullptr) {
31023     return;
31024   }
31025 
31026   bool has_bots = !bot_user_ids.empty();
31027   if (!d->is_has_bots_inited || d->has_bots != has_bots) {
31028     set_dialog_has_bots(d, has_bots);
31029     on_dialog_updated(dialog_id, "on_dialog_bots_updated");
31030   }
31031 
31032   if (d->reply_markup_message_id != MessageId()) {
31033     const Message *m = get_message_force(d, d->reply_markup_message_id, "on_dialog_bots_updated");
31034     if (m == nullptr || (m->sender_user_id.is_valid() && !td::contains(bot_user_ids, m->sender_user_id))) {
31035       LOG(INFO) << "Remove reply markup in " << dialog_id << ", because bot "
31036                 << (m == nullptr ? UserId() : m->sender_user_id) << " isn't a member of the chat";
31037       set_dialog_reply_markup(d, MessageId());
31038     }
31039   }
31040 }
31041 
set_dialog_has_bots(Dialog * d,bool has_bots)31042 void MessagesManager::set_dialog_has_bots(Dialog *d, bool has_bots) {
31043   CHECK(d != nullptr);
31044   LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in set_dialog_has_bots";
31045 
31046   LOG(INFO) << "Set " << d->dialog_id << " has_bots to " << has_bots;
31047 
31048   auto old_skip_bot_commands = need_skip_bot_commands(d->dialog_id, nullptr);
31049   d->has_bots = has_bots;
31050   d->is_has_bots_inited = true;
31051   auto new_skip_bot_commands = need_skip_bot_commands(d->dialog_id, nullptr);
31052   if (old_skip_bot_commands != new_skip_bot_commands) {
31053     auto it = dialog_bot_command_message_ids_.find(d->dialog_id);
31054     if (it != dialog_bot_command_message_ids_.end()) {
31055       for (auto message_id : it->second.message_ids) {
31056         auto m = get_message(d, message_id);
31057         LOG_CHECK(m != nullptr) << d->dialog_id << ' ' << message_id;
31058         send_update_message_content_impl(d->dialog_id, m, "set_dialog_has_bots");
31059       }
31060     }
31061   }
31062 }
31063 
on_dialog_photo_updated(DialogId dialog_id)31064 void MessagesManager::on_dialog_photo_updated(DialogId dialog_id) {
31065   auto d = get_dialog(dialog_id);  // called from update_user, must not create the dialog
31066   if (d != nullptr && d->is_update_new_chat_sent) {
31067     send_closure(
31068         G()->td(), &Td::send_update,
31069         make_tl_object<td_api::updateChatPhoto>(
31070             dialog_id.get(), get_chat_photo_info_object(td_->file_manager_.get(), get_dialog_photo(dialog_id))));
31071   }
31072 }
31073 
on_dialog_title_updated(DialogId dialog_id)31074 void MessagesManager::on_dialog_title_updated(DialogId dialog_id) {
31075   auto d = get_dialog(dialog_id);  // called from update_user, must not create the dialog
31076   if (d != nullptr) {
31077     update_dialogs_hints(d);
31078     if (d->is_update_new_chat_sent) {
31079       send_closure(G()->td(), &Td::send_update,
31080                    make_tl_object<td_api::updateChatTitle>(dialog_id.get(), get_dialog_title(dialog_id)));
31081     }
31082   }
31083 }
31084 
on_dialog_default_permissions_updated(DialogId dialog_id)31085 void MessagesManager::on_dialog_default_permissions_updated(DialogId dialog_id) {
31086   auto d = get_dialog(dialog_id);  // called from update_user, must not create the dialog
31087   if (d != nullptr && d->is_update_new_chat_sent) {
31088     send_closure(G()->td(), &Td::send_update,
31089                  td_api::make_object<td_api::updateChatPermissions>(
31090                      dialog_id.get(), get_dialog_default_permissions(dialog_id).get_chat_permissions_object()));
31091   }
31092 }
31093 
on_dialog_has_protected_content_updated(DialogId dialog_id)31094 void MessagesManager::on_dialog_has_protected_content_updated(DialogId dialog_id) {
31095   auto d = get_dialog(dialog_id);  // called from update_chat, must not create the dialog
31096   if (d != nullptr && d->is_update_new_chat_sent) {
31097     send_closure(G()->td(), &Td::send_update,
31098                  td_api::make_object<td_api::updateChatHasProtectedContent>(
31099                      dialog_id.get(), get_dialog_has_protected_content(dialog_id)));
31100   }
31101 }
31102 
on_dialog_user_is_contact_updated(DialogId dialog_id,bool is_contact)31103 void MessagesManager::on_dialog_user_is_contact_updated(DialogId dialog_id, bool is_contact) {
31104   CHECK(dialog_id.get_type() == DialogType::User);
31105   auto d = get_dialog(dialog_id);  // called from update_user, must not create the dialog
31106   if (d != nullptr && d->is_update_new_chat_sent) {
31107     if (d->know_action_bar) {
31108       if (is_contact) {
31109         if (d->action_bar != nullptr && d->action_bar->on_user_contact_added()) {
31110           send_update_chat_action_bar(d);
31111         }
31112       } else {
31113         repair_dialog_action_bar(d, "on_dialog_user_is_contact_updated");
31114       }
31115     }
31116 
31117     if (!dialog_filters_.empty() && d->order != DEFAULT_ORDER) {
31118       update_dialog_lists(d, get_dialog_positions(d), true, false, "on_dialog_user_is_contact_updated");
31119       td_->contacts_manager_->for_each_secret_chat_with_user(
31120           d->dialog_id.get_user_id(), [this](SecretChatId secret_chat_id) {
31121             DialogId dialog_id(secret_chat_id);
31122             auto d = get_dialog(dialog_id);  // must not create the dialog
31123             if (d != nullptr && d->is_update_new_chat_sent && d->order != DEFAULT_ORDER) {
31124               update_dialog_lists(d, get_dialog_positions(d), true, false, "on_dialog_user_is_contact_updated");
31125             }
31126           });
31127     }
31128   }
31129 }
31130 
on_dialog_user_is_deleted_updated(DialogId dialog_id,bool is_deleted)31131 void MessagesManager::on_dialog_user_is_deleted_updated(DialogId dialog_id, bool is_deleted) {
31132   CHECK(dialog_id.get_type() == DialogType::User);
31133   auto d = get_dialog(dialog_id);  // called from update_user, must not create the dialog
31134   if (d != nullptr && d->is_update_new_chat_sent) {
31135     if (d->know_action_bar) {
31136       if (is_deleted) {
31137         if (d->action_bar != nullptr && d->action_bar->on_user_deleted()) {
31138           send_update_chat_action_bar(d);
31139         }
31140       } else {
31141         repair_dialog_action_bar(d, "on_dialog_user_is_deleted_updated");
31142       }
31143     }
31144 
31145     if (!dialog_filters_.empty() && d->order != DEFAULT_ORDER) {
31146       update_dialog_lists(d, get_dialog_positions(d), true, false, "on_dialog_user_is_deleted_updated");
31147       td_->contacts_manager_->for_each_secret_chat_with_user(
31148           dialog_id.get_user_id(), [this](SecretChatId secret_chat_id) {
31149             DialogId dialog_id(secret_chat_id);
31150             auto d = get_dialog(dialog_id);  // must not create the dialog
31151             if (d != nullptr && d->is_update_new_chat_sent && d->order != DEFAULT_ORDER) {
31152               update_dialog_lists(d, get_dialog_positions(d), true, false, "on_dialog_user_is_deleted_updated");
31153             }
31154           });
31155     }
31156 
31157     if (is_deleted && d->has_bots) {
31158       set_dialog_has_bots(d, false);
31159       td_->contacts_manager_->for_each_secret_chat_with_user(
31160           dialog_id.get_user_id(), [this](SecretChatId secret_chat_id) {
31161             DialogId dialog_id(secret_chat_id);
31162             auto d = get_dialog(dialog_id);  // must not create the dialog
31163             if (d != nullptr && d->is_update_new_chat_sent && d->has_bots) {
31164               set_dialog_has_bots(d, false);
31165             }
31166           });
31167     }
31168   }
31169 }
31170 
on_dialog_linked_channel_updated(DialogId dialog_id,ChannelId old_linked_channel_id,ChannelId new_linked_channel_id) const31171 void MessagesManager::on_dialog_linked_channel_updated(DialogId dialog_id, ChannelId old_linked_channel_id,
31172                                                        ChannelId new_linked_channel_id) const {
31173   CHECK(dialog_id.get_type() == DialogType::Channel);
31174   if (!is_broadcast_channel(dialog_id)) {
31175     return;
31176   }
31177   auto d = get_dialog(dialog_id);  // no need to create the dialog
31178   if (d != nullptr && d->is_update_new_chat_sent) {
31179     vector<MessageId> message_ids;
31180     find_messages(d->messages.get(), message_ids, [old_linked_channel_id, new_linked_channel_id](const Message *m) {
31181       return !m->reply_info.is_empty() && m->reply_info.channel_id.is_valid() &&
31182              (m->reply_info.channel_id == old_linked_channel_id || m->reply_info.channel_id == new_linked_channel_id);
31183     });
31184     LOG(INFO) << "Found discussion messages " << message_ids;
31185     for (auto message_id : message_ids) {
31186       send_update_message_interaction_info(dialog_id, get_message(d, message_id));
31187       if (message_id == d->last_message_id) {
31188         send_update_chat_last_message_impl(d, "on_dialog_linked_channel_updated");
31189       }
31190     }
31191   }
31192 }
31193 
resolve_dialog_username(const string & username) const31194 DialogId MessagesManager::resolve_dialog_username(const string &username) const {
31195   auto cleaned_username = clean_username(username);
31196   auto it = resolved_usernames_.find(cleaned_username);
31197   if (it != resolved_usernames_.end()) {
31198     return it->second.dialog_id;
31199   }
31200 
31201   auto it2 = inaccessible_resolved_usernames_.find(cleaned_username);
31202   if (it2 != inaccessible_resolved_usernames_.end()) {
31203     return it2->second;
31204   }
31205 
31206   return DialogId();
31207 }
31208 
search_public_dialog(const string & username_to_search,bool force,Promise<Unit> && promise)31209 DialogId MessagesManager::search_public_dialog(const string &username_to_search, bool force, Promise<Unit> &&promise) {
31210   string username = clean_username(username_to_search);
31211   if (username[0] == '@') {
31212     username = username.substr(1);
31213   }
31214   if (username.empty()) {
31215     promise.set_error(Status::Error(200, "Username is invalid"));
31216     return DialogId();
31217   }
31218 
31219   DialogId dialog_id;
31220   auto it = resolved_usernames_.find(username);
31221   if (it != resolved_usernames_.end()) {
31222     if (it->second.expires_at < Time::now()) {
31223       td_->create_handler<ResolveUsernameQuery>(Promise<>())->send(username);
31224     }
31225     dialog_id = it->second.dialog_id;
31226   } else {
31227     auto it2 = inaccessible_resolved_usernames_.find(username);
31228     if (it2 != inaccessible_resolved_usernames_.end()) {
31229       dialog_id = it2->second;
31230     }
31231   }
31232 
31233   if (dialog_id.is_valid()) {
31234     if (have_input_peer(dialog_id, AccessRights::Read)) {
31235       if (!force && reload_voice_chat_on_search_usernames_.count(username)) {
31236         reload_voice_chat_on_search_usernames_.erase(username);
31237         if (dialog_id.get_type() == DialogType::Channel) {
31238           td_->contacts_manager_->reload_channel_full(dialog_id.get_channel_id(), std::move(promise),
31239                                                       "search_public_dialog");
31240           return DialogId();
31241         }
31242       }
31243 
31244       if (td_->auth_manager_->is_bot()) {
31245         force_create_dialog(dialog_id, "search_public_dialog", true);
31246       } else {
31247         const Dialog *d = get_dialog_force(dialog_id, "search_public_dialog");
31248         if (!is_dialog_inited(d)) {
31249           send_get_dialog_query(dialog_id, std::move(promise), 0, "search_public_dialog");
31250           return DialogId();
31251         }
31252       }
31253 
31254       promise.set_value(Unit());
31255       return dialog_id;
31256     } else {
31257       // bot username maybe known despite there is no access_hash
31258       if (force || dialog_id.get_type() != DialogType::User) {
31259         force_create_dialog(dialog_id, "search_public_dialog", true);
31260         promise.set_value(Unit());
31261         return dialog_id;
31262       }
31263     }
31264   }
31265 
31266   td_->create_handler<ResolveUsernameQuery>(std::move(promise))->send(username);
31267   return DialogId();
31268 }
31269 
reload_voice_chat_on_search(const string & username)31270 void MessagesManager::reload_voice_chat_on_search(const string &username) {
31271   reload_voice_chat_on_search_usernames_.insert(clean_username(username));
31272 }
31273 
send_get_dialog_notification_settings_query(DialogId dialog_id,Promise<Unit> && promise)31274 void MessagesManager::send_get_dialog_notification_settings_query(DialogId dialog_id, Promise<Unit> &&promise) {
31275   if (td_->auth_manager_->is_bot() || dialog_id.get_type() == DialogType::SecretChat) {
31276     LOG(WARNING) << "Can't get notification settings for " << dialog_id;
31277     return promise.set_error(Status::Error(500, "Wrong getDialogNotificationSettings query"));
31278   }
31279   if (!have_input_peer(dialog_id, AccessRights::Read)) {
31280     LOG(WARNING) << "Have no access to " << dialog_id << " to get notification settings";
31281     return promise.set_error(Status::Error(400, "Can't access the chat"));
31282   }
31283 
31284   auto &promises = get_dialog_notification_settings_queries_[dialog_id];
31285   promises.push_back(std::move(promise));
31286   if (promises.size() != 1) {
31287     // query has already been sent, just wait for the result
31288     return;
31289   }
31290 
31291   td_->create_handler<GetDialogNotifySettingsQuery>()->send(dialog_id);
31292 }
31293 
send_get_scope_notification_settings_query(NotificationSettingsScope scope,Promise<Unit> && promise)31294 void MessagesManager::send_get_scope_notification_settings_query(NotificationSettingsScope scope,
31295                                                                  Promise<Unit> &&promise) {
31296   if (td_->auth_manager_->is_bot()) {
31297     LOG(ERROR) << "Can't get notification settings for " << scope;
31298     return promise.set_error(Status::Error(500, "Wrong getScopeNotificationSettings query"));
31299   }
31300 
31301   td_->create_handler<GetScopeNotifySettingsQuery>(std::move(promise))->send(scope);
31302 }
31303 
on_get_dialog_notification_settings_query_finished(DialogId dialog_id,Status && status)31304 void MessagesManager::on_get_dialog_notification_settings_query_finished(DialogId dialog_id, Status &&status) {
31305   CHECK(!td_->auth_manager_->is_bot());
31306   auto it = get_dialog_notification_settings_queries_.find(dialog_id);
31307   CHECK(it != get_dialog_notification_settings_queries_.end());
31308   CHECK(!it->second.empty());
31309   auto promises = std::move(it->second);
31310   get_dialog_notification_settings_queries_.erase(it);
31311 
31312   for (auto &promise : promises) {
31313     if (status.is_ok()) {
31314       promise.set_value(Unit());
31315     } else {
31316       promise.set_error(status.clone());
31317     }
31318   }
31319 }
31320 
31321 class MessagesManager::RegetDialogLogEvent {
31322  public:
31323   DialogId dialog_id_;
31324 
31325   template <class StorerT>
store(StorerT & storer) const31326   void store(StorerT &storer) const {
31327     td::store(dialog_id_, storer);
31328   }
31329 
31330   template <class ParserT>
parse(ParserT & parser)31331   void parse(ParserT &parser) {
31332     td::parse(dialog_id_, parser);
31333   }
31334 };
31335 
save_reget_dialog_log_event(DialogId dialog_id)31336 uint64 MessagesManager::save_reget_dialog_log_event(DialogId dialog_id) {
31337   RegetDialogLogEvent log_event{dialog_id};
31338   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::RegetDialog, get_log_event_storer(log_event));
31339 }
31340 
send_get_dialog_query(DialogId dialog_id,Promise<Unit> && promise,uint64 log_event_id,const char * source)31341 void MessagesManager::send_get_dialog_query(DialogId dialog_id, Promise<Unit> &&promise, uint64 log_event_id,
31342                                             const char *source) {
31343   TRY_STATUS_PROMISE(promise, G()->close_status());
31344 
31345   if (td_->auth_manager_->is_bot() || dialog_id.get_type() == DialogType::SecretChat) {
31346     if (log_event_id != 0) {
31347       binlog_erase(G()->td_db()->get_binlog(), log_event_id);
31348     }
31349     return promise.set_error(Status::Error(500, "Wrong getDialog query"));
31350   }
31351   if (!have_input_peer(dialog_id, AccessRights::Read)) {
31352     if (log_event_id != 0) {
31353       binlog_erase(G()->td_db()->get_binlog(), log_event_id);
31354     }
31355     return promise.set_error(Status::Error(400, "Can't access the chat"));
31356   }
31357 
31358   auto &promises = get_dialog_queries_[dialog_id];
31359   promises.push_back(std::move(promise));
31360   if (promises.size() != 1) {
31361     if (log_event_id != 0) {
31362       LOG(INFO) << "Duplicate getDialog query for " << dialog_id << " from " << source;
31363       binlog_erase(G()->td_db()->get_binlog(), log_event_id);
31364     }
31365     // query has already been sent, just wait for the result
31366     return;
31367   }
31368 
31369   if (log_event_id == 0 && G()->parameters().use_message_db) {
31370     log_event_id = save_reget_dialog_log_event(dialog_id);
31371   }
31372   if (log_event_id != 0) {
31373     auto result = get_dialog_query_log_event_id_.emplace(dialog_id, log_event_id);
31374     CHECK(result.second);
31375   }
31376   if (G()->close_flag()) {
31377     // request will be sent after restart
31378     return;
31379   }
31380 
31381   LOG(INFO) << "Send get " << dialog_id << " query from " << source;
31382   td_->create_handler<GetDialogQuery>()->send(dialog_id);
31383 }
31384 
on_get_dialog_query_finished(DialogId dialog_id,Status && status)31385 void MessagesManager::on_get_dialog_query_finished(DialogId dialog_id, Status &&status) {
31386   if (G()->close_flag()) {
31387     return;
31388   }
31389 
31390   LOG(INFO) << "Finished getting " << dialog_id << " with result " << status;
31391   auto it = get_dialog_queries_.find(dialog_id);
31392   CHECK(it != get_dialog_queries_.end());
31393   CHECK(!it->second.empty());
31394   auto promises = std::move(it->second);
31395   get_dialog_queries_.erase(it);
31396 
31397   auto log_event_it = get_dialog_query_log_event_id_.find(dialog_id);
31398   if (log_event_it != get_dialog_query_log_event_id_.end()) {
31399     if (!G()->close_flag()) {
31400       binlog_erase(G()->td_db()->get_binlog(), log_event_it->second);
31401     }
31402     get_dialog_query_log_event_id_.erase(log_event_it);
31403   }
31404 
31405   for (auto &promise : promises) {
31406     if (status.is_ok()) {
31407       promise.set_value(Unit());
31408     } else {
31409       promise.set_error(status.clone());
31410     }
31411   }
31412 }
31413 
is_update_about_username_change_received(DialogId dialog_id) const31414 bool MessagesManager::is_update_about_username_change_received(DialogId dialog_id) const {
31415   switch (dialog_id.get_type()) {
31416     case DialogType::User:
31417       return td_->contacts_manager_->is_update_about_username_change_received(dialog_id.get_user_id());
31418     case DialogType::Chat:
31419       return true;
31420     case DialogType::Channel:
31421       return td_->contacts_manager_->get_channel_status(dialog_id.get_channel_id()).is_member();
31422     case DialogType::SecretChat:
31423       return true;
31424     case DialogType::None:
31425     default:
31426       UNREACHABLE();
31427       return false;
31428   }
31429 }
31430 
on_dialog_username_updated(DialogId dialog_id,const string & old_username,const string & new_username)31431 void MessagesManager::on_dialog_username_updated(DialogId dialog_id, const string &old_username,
31432                                                  const string &new_username) {
31433   auto d = get_dialog(dialog_id);
31434   if (d != nullptr) {
31435     update_dialogs_hints(d);
31436   }
31437   if (old_username != new_username) {
31438     message_embedding_codes_[0].erase(dialog_id);
31439     message_embedding_codes_[1].erase(dialog_id);
31440   }
31441   if (!old_username.empty() && old_username != new_username) {
31442     resolved_usernames_.erase(clean_username(old_username));
31443     inaccessible_resolved_usernames_.erase(clean_username(old_username));
31444   }
31445   if (!new_username.empty()) {
31446     auto cache_time = is_update_about_username_change_received(dialog_id) ? USERNAME_CACHE_EXPIRE_TIME
31447                                                                           : USERNAME_CACHE_EXPIRE_TIME_SHORT;
31448     resolved_usernames_[clean_username(new_username)] = ResolvedUsername{dialog_id, Time::now() + cache_time};
31449   }
31450 }
31451 
on_resolved_username(const string & username,DialogId dialog_id)31452 void MessagesManager::on_resolved_username(const string &username, DialogId dialog_id) {
31453   if (!dialog_id.is_valid()) {
31454     LOG(ERROR) << "Resolve username \"" << username << "\" to invalid " << dialog_id;
31455     return;
31456   }
31457 
31458   auto it = resolved_usernames_.find(clean_username(username));
31459   if (it != resolved_usernames_.end()) {
31460     LOG_IF(ERROR, it->second.dialog_id != dialog_id)
31461         << "Resolve username \"" << username << "\" to " << dialog_id << ", but have it in " << it->second.dialog_id;
31462     return;
31463   }
31464 
31465   inaccessible_resolved_usernames_[clean_username(username)] = dialog_id;
31466 }
31467 
drop_username(const string & username)31468 void MessagesManager::drop_username(const string &username) {
31469   inaccessible_resolved_usernames_.erase(clean_username(username));
31470 
31471   auto it = resolved_usernames_.find(clean_username(username));
31472   if (it == resolved_usernames_.end()) {
31473     return;
31474   }
31475 
31476   auto dialog_id = it->second.dialog_id;
31477   if (have_input_peer(dialog_id, AccessRights::Read)) {
31478     CHECK(dialog_id.get_type() != DialogType::SecretChat);
31479     send_get_dialog_query(dialog_id, Auto(), 0, "drop_username");
31480   }
31481 
31482   resolved_usernames_.erase(it);
31483 }
31484 
get_dialog_photo(DialogId dialog_id) const31485 const DialogPhoto *MessagesManager::get_dialog_photo(DialogId dialog_id) const {
31486   switch (dialog_id.get_type()) {
31487     case DialogType::User:
31488       return td_->contacts_manager_->get_user_dialog_photo(dialog_id.get_user_id());
31489     case DialogType::Chat:
31490       return td_->contacts_manager_->get_chat_dialog_photo(dialog_id.get_chat_id());
31491     case DialogType::Channel:
31492       return td_->contacts_manager_->get_channel_dialog_photo(dialog_id.get_channel_id());
31493     case DialogType::SecretChat:
31494       return td_->contacts_manager_->get_secret_chat_dialog_photo(dialog_id.get_secret_chat_id());
31495     case DialogType::None:
31496     default:
31497       UNREACHABLE();
31498       return nullptr;
31499   }
31500 }
31501 
get_dialog_title(DialogId dialog_id) const31502 string MessagesManager::get_dialog_title(DialogId dialog_id) const {
31503   switch (dialog_id.get_type()) {
31504     case DialogType::User:
31505       return td_->contacts_manager_->get_user_title(dialog_id.get_user_id());
31506     case DialogType::Chat:
31507       return td_->contacts_manager_->get_chat_title(dialog_id.get_chat_id());
31508     case DialogType::Channel:
31509       return td_->contacts_manager_->get_channel_title(dialog_id.get_channel_id());
31510     case DialogType::SecretChat:
31511       return td_->contacts_manager_->get_secret_chat_title(dialog_id.get_secret_chat_id());
31512     case DialogType::None:
31513     default:
31514       UNREACHABLE();
31515       return string();
31516   }
31517 }
31518 
get_dialog_username(DialogId dialog_id) const31519 string MessagesManager::get_dialog_username(DialogId dialog_id) const {
31520   switch (dialog_id.get_type()) {
31521     case DialogType::User:
31522       return td_->contacts_manager_->get_user_username(dialog_id.get_user_id());
31523     case DialogType::Chat:
31524       return string();
31525     case DialogType::Channel:
31526       return td_->contacts_manager_->get_channel_username(dialog_id.get_channel_id());
31527     case DialogType::SecretChat:
31528       return td_->contacts_manager_->get_secret_chat_username(dialog_id.get_secret_chat_id());
31529     case DialogType::None:
31530     default:
31531       UNREACHABLE();
31532       return string();
31533   }
31534 }
31535 
get_dialog_default_permissions(DialogId dialog_id) const31536 RestrictedRights MessagesManager::get_dialog_default_permissions(DialogId dialog_id) const {
31537   switch (dialog_id.get_type()) {
31538     case DialogType::User:
31539       return td_->contacts_manager_->get_user_default_permissions(dialog_id.get_user_id());
31540     case DialogType::Chat:
31541       return td_->contacts_manager_->get_chat_default_permissions(dialog_id.get_chat_id());
31542     case DialogType::Channel:
31543       return td_->contacts_manager_->get_channel_default_permissions(dialog_id.get_channel_id());
31544     case DialogType::SecretChat:
31545       return td_->contacts_manager_->get_secret_chat_default_permissions(dialog_id.get_secret_chat_id());
31546     case DialogType::None:
31547     default:
31548       UNREACHABLE();
31549       return RestrictedRights(false, false, false, false, false, false, false, false, false, false, false);
31550   }
31551 }
31552 
get_dialog_has_protected_content(DialogId dialog_id) const31553 bool MessagesManager::get_dialog_has_protected_content(DialogId dialog_id) const {
31554   switch (dialog_id.get_type()) {
31555     case DialogType::User:
31556       return false;
31557     case DialogType::Chat:
31558       return td_->contacts_manager_->get_chat_has_protected_content(dialog_id.get_chat_id());
31559     case DialogType::Channel:
31560       return td_->contacts_manager_->get_channel_has_protected_content(dialog_id.get_channel_id());
31561     case DialogType::SecretChat:
31562       return false;
31563     case DialogType::None:
31564     default:
31565       UNREACHABLE();
31566       return true;
31567   }
31568 }
31569 
get_dialog_has_scheduled_messages(const Dialog * d) const31570 bool MessagesManager::get_dialog_has_scheduled_messages(const Dialog *d) const {
31571   if (!have_input_peer(d->dialog_id, AccessRights::Read)) {
31572     return false;
31573   }
31574   if (is_broadcast_channel(d->dialog_id) &&
31575       !td_->contacts_manager_->get_channel_status(d->dialog_id.get_channel_id()).can_post_messages()) {
31576     return false;
31577   }
31578   // TODO send updateChatHasScheduledMessage when can_post_messages changes
31579 
31580   return d->has_scheduled_server_messages || d->has_scheduled_database_messages || d->scheduled_messages != nullptr;
31581 }
31582 
is_dialog_action_unneeded(DialogId dialog_id) const31583 bool MessagesManager::is_dialog_action_unneeded(DialogId dialog_id) const {
31584   if (is_anonymous_administrator(dialog_id, nullptr)) {
31585     return true;
31586   }
31587 
31588   auto dialog_type = dialog_id.get_type();
31589   if (dialog_type == DialogType::User || dialog_type == DialogType::SecretChat) {
31590     UserId user_id = dialog_type == DialogType::User
31591                          ? dialog_id.get_user_id()
31592                          : td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id());
31593     if (td_->contacts_manager_->is_user_deleted(user_id)) {
31594       return true;
31595     }
31596     if (td_->contacts_manager_->is_user_bot(user_id) && !td_->contacts_manager_->is_user_support(user_id)) {
31597       return true;
31598     }
31599     if (user_id == td_->contacts_manager_->get_my_id()) {
31600       return true;
31601     }
31602 
31603     if (!td_->auth_manager_->is_bot()) {
31604       if (td_->contacts_manager_->is_user_status_exact(user_id)) {
31605         if (!td_->contacts_manager_->is_user_online(user_id, 30)) {
31606           return true;
31607         }
31608       } else {
31609         // return true;
31610       }
31611     }
31612   }
31613   return false;
31614 }
31615 
send_dialog_action(DialogId dialog_id,MessageId top_thread_message_id,DialogAction action,Promise<Unit> && promise)31616 void MessagesManager::send_dialog_action(DialogId dialog_id, MessageId top_thread_message_id, DialogAction action,
31617                                          Promise<Unit> &&promise) {
31618   if (!have_dialog_force(dialog_id, "send_dialog_action")) {
31619     return promise.set_error(Status::Error(400, "Chat not found"));
31620   }
31621   if (top_thread_message_id != MessageId() &&
31622       (!top_thread_message_id.is_valid() || !top_thread_message_id.is_server())) {
31623     return promise.set_error(Status::Error(400, "Invalid message thread specified"));
31624   }
31625 
31626   tl_object_ptr<telegram_api::InputPeer> input_peer;
31627   if (action == DialogAction::get_speaking_action()) {
31628     input_peer = get_input_peer(dialog_id, AccessRights::Read);
31629     if (input_peer == nullptr) {
31630       return promise.set_error(Status::Error(400, "Have no access to the chat"));
31631     }
31632   } else {
31633     auto can_send_status = can_send_message(dialog_id);
31634     if (can_send_status.is_error()) {
31635       if (td_->auth_manager_->is_bot()) {
31636         return promise.set_error(can_send_status.move_as_error());
31637       }
31638       return promise.set_value(Unit());
31639     }
31640 
31641     if (is_dialog_action_unneeded(dialog_id)) {
31642       return promise.set_value(Unit());
31643     }
31644 
31645     input_peer = get_input_peer(dialog_id, AccessRights::Write);
31646   }
31647 
31648   if (dialog_id.get_type() == DialogType::SecretChat) {
31649     send_closure(G()->secret_chats_manager(), &SecretChatsManager::send_message_action, dialog_id.get_secret_chat_id(),
31650                  action.get_secret_input_send_message_action());
31651     promise.set_value(Unit());
31652     return;
31653   }
31654 
31655   auto &query_ref = set_typing_query_[dialog_id];
31656   if (!query_ref.empty() && !td_->auth_manager_->is_bot()) {
31657     LOG(INFO) << "Cancel previous send chat action query";
31658     cancel_query(query_ref);
31659   }
31660   query_ref =
31661       td_->create_handler<SetTypingQuery>(std::move(promise))
31662           ->send(dialog_id, std::move(input_peer), top_thread_message_id, action.get_input_send_message_action());
31663 }
31664 
after_set_typing_query(DialogId dialog_id,int32 generation)31665 void MessagesManager::after_set_typing_query(DialogId dialog_id, int32 generation) {
31666   auto it = set_typing_query_.find(dialog_id);
31667   if (it != set_typing_query_.end() && (!it->second.is_alive() || it->second.generation() == generation)) {
31668     set_typing_query_.erase(it);
31669   }
31670 }
31671 
on_send_dialog_action_timeout(DialogId dialog_id)31672 void MessagesManager::on_send_dialog_action_timeout(DialogId dialog_id) {
31673   LOG(INFO) << "Receive send_chat_action timeout in " << dialog_id;
31674   Dialog *d = get_dialog(dialog_id);
31675   CHECK(d != nullptr);
31676 
31677   if (can_send_message(dialog_id).is_error()) {
31678     return;
31679   }
31680 
31681   auto queue_id = get_sequence_dispatcher_id(dialog_id, MessageContentType::Photo);
31682   CHECK(queue_id & 1);
31683 
31684   auto queue_it = yet_unsent_media_queues_.find(queue_id);
31685   if (queue_it == yet_unsent_media_queues_.end()) {
31686     return;
31687   }
31688 
31689   pending_send_dialog_action_timeout_.add_timeout_in(dialog_id.get(), 4.0);
31690 
31691   CHECK(!queue_it->second.empty());
31692   const Message *m = get_message(d, queue_it->second.begin()->first);
31693   if (m == nullptr) {
31694     return;
31695   }
31696   CHECK(m->message_id.is_yet_unsent());
31697   if (m->forward_info != nullptr || m->had_forward_info || m->message_id.is_scheduled() ||
31698       m->sender_dialog_id.is_valid()) {
31699     return;
31700   }
31701 
31702   auto file_id = get_message_content_upload_file_id(m->content.get());
31703   if (!file_id.is_valid()) {
31704     LOG(ERROR) << "Have no file in "
31705                << to_string(get_message_content_object(m->content.get(), td_, dialog_id, m->date, m->is_content_secret,
31706                                                        false, -1));
31707     return;
31708   }
31709   auto file_view = td_->file_manager_->get_file_view(file_id);
31710   if (!file_view.is_uploading()) {
31711     return;
31712   }
31713   int64 total_size = file_view.expected_size();
31714   int64 uploaded_size = file_view.remote_size();
31715   int32 progress = 0;
31716   if (total_size > 0 && uploaded_size > 0) {
31717     if (uploaded_size > total_size) {
31718       uploaded_size = total_size;  // just in case
31719     }
31720     progress = static_cast<int32>(100 * uploaded_size / total_size);
31721   }
31722 
31723   DialogAction action = DialogAction::get_uploading_action(m->content->get_type(), progress);
31724   if (action == DialogAction()) {
31725     return;
31726   }
31727   LOG(INFO) << "Send " << action << " in " << dialog_id;
31728   send_dialog_action(dialog_id, m->top_thread_message_id, std::move(action), Promise<Unit>());
31729 }
31730 
on_active_dialog_action_timeout(DialogId dialog_id)31731 void MessagesManager::on_active_dialog_action_timeout(DialogId dialog_id) {
31732   LOG(DEBUG) << "Receive active dialog action timeout in " << dialog_id;
31733   auto actions_it = active_dialog_actions_.find(dialog_id);
31734   if (actions_it == active_dialog_actions_.end()) {
31735     return;
31736   }
31737   CHECK(!actions_it->second.empty());
31738 
31739   auto now = Time::now();
31740   DialogId prev_typing_dialog_id;
31741   while (actions_it->second[0].start_time + DIALOG_ACTION_TIMEOUT < now + 0.1) {
31742     CHECK(actions_it->second[0].typing_dialog_id != prev_typing_dialog_id);
31743     prev_typing_dialog_id = actions_it->second[0].typing_dialog_id;
31744     on_dialog_action(dialog_id, actions_it->second[0].top_thread_message_id, actions_it->second[0].typing_dialog_id,
31745                      DialogAction(), 0);
31746 
31747     actions_it = active_dialog_actions_.find(dialog_id);
31748     if (actions_it == active_dialog_actions_.end()) {
31749       return;
31750     }
31751     CHECK(!actions_it->second.empty());
31752   }
31753 
31754   LOG(DEBUG) << "Schedule next action timeout in " << dialog_id;
31755   active_dialog_action_timeout_.add_timeout_in(dialog_id.get(),
31756                                                actions_it->second[0].start_time + DIALOG_ACTION_TIMEOUT - now);
31757 }
31758 
clear_active_dialog_actions(DialogId dialog_id)31759 void MessagesManager::clear_active_dialog_actions(DialogId dialog_id) {
31760   LOG(DEBUG) << "Clear active dialog actions in " << dialog_id;
31761   auto actions_it = active_dialog_actions_.find(dialog_id);
31762   while (actions_it != active_dialog_actions_.end()) {
31763     CHECK(!actions_it->second.empty());
31764     on_dialog_action(dialog_id, actions_it->second[0].top_thread_message_id, actions_it->second[0].typing_dialog_id,
31765                      DialogAction(), 0);
31766     actions_it = active_dialog_actions_.find(dialog_id);
31767   }
31768 }
31769 
get_dialog_lists_to_add_dialog(DialogId dialog_id)31770 vector<DialogListId> MessagesManager::get_dialog_lists_to_add_dialog(DialogId dialog_id) {
31771   vector<DialogListId> result;
31772   const Dialog *d = get_dialog_force(dialog_id, "get_dialog_lists_to_add_dialog");
31773   if (d == nullptr || d->order == DEFAULT_ORDER || !have_input_peer(dialog_id, AccessRights::Read)) {
31774     return result;
31775   }
31776 
31777   if (dialog_id != get_my_dialog_id() && dialog_id != DialogId(ContactsManager::get_service_notifications_user_id())) {
31778     result.push_back(DialogListId(d->folder_id == FolderId::archive() ? FolderId::main() : FolderId::archive()));
31779   }
31780 
31781   for (const auto &dialog_filter : dialog_filters_) {
31782     auto dialog_filter_id = dialog_filter->dialog_filter_id;
31783     if (!InputDialogId::contains(dialog_filter->included_dialog_ids, dialog_id) &&
31784         !InputDialogId::contains(dialog_filter->pinned_dialog_ids, dialog_id)) {
31785       // the dialog isn't added yet to the dialog list
31786       // check that it can be actually added
31787       if (dialog_filter->included_dialog_ids.size() + dialog_filter->pinned_dialog_ids.size() <
31788           DialogFilter::MAX_INCLUDED_FILTER_DIALOGS) {
31789         // fast path
31790         result.push_back(DialogListId(dialog_filter_id));
31791         continue;
31792       }
31793 
31794       auto new_dialog_filter = make_unique<DialogFilter>(*dialog_filter);
31795       new_dialog_filter->included_dialog_ids.push_back(get_input_dialog_id(dialog_id));
31796       td::remove_if(new_dialog_filter->excluded_dialog_ids, [dialog_id](InputDialogId input_dialog_id) {
31797         return dialog_id == input_dialog_id.get_dialog_id();
31798       });
31799 
31800       if (new_dialog_filter->check_limits().is_ok()) {
31801         result.push_back(DialogListId(dialog_filter_id));
31802       }
31803     }
31804   }
31805   return result;
31806 }
31807 
add_dialog_to_list(DialogId dialog_id,DialogListId dialog_list_id,Promise<Unit> && promise)31808 void MessagesManager::add_dialog_to_list(DialogId dialog_id, DialogListId dialog_list_id, Promise<Unit> &&promise) {
31809   LOG(INFO) << "Receive addChatToList request to add " << dialog_id << " to " << dialog_list_id;
31810   CHECK(!td_->auth_manager_->is_bot());
31811 
31812   Dialog *d = get_dialog_force(dialog_id, "add_dialog_to_list");
31813   if (d == nullptr) {
31814     return promise.set_error(Status::Error(400, "Chat not found"));
31815   }
31816   if (!have_input_peer(dialog_id, AccessRights::Read)) {
31817     return promise.set_error(Status::Error(400, "Can't access the chat"));
31818   }
31819 
31820   if (d->order == DEFAULT_ORDER) {
31821     return promise.set_error(Status::Error(400, "Chat is not in a chat list"));
31822   }
31823 
31824   if (get_dialog_list(dialog_list_id) == nullptr) {
31825     return promise.set_error(Status::Error(400, "Chat list not found"));
31826   }
31827 
31828   if (dialog_list_id.is_filter()) {
31829     CHECK(is_update_chat_filters_sent_);
31830     auto dialog_filter_id = dialog_list_id.get_filter_id();
31831     auto old_dialog_filter = get_dialog_filter(dialog_filter_id);
31832     CHECK(old_dialog_filter != nullptr);
31833     if (InputDialogId::contains(old_dialog_filter->included_dialog_ids, dialog_id) ||
31834         InputDialogId::contains(old_dialog_filter->pinned_dialog_ids, dialog_id)) {
31835       return promise.set_value(Unit());
31836     }
31837 
31838     auto new_dialog_filter = make_unique<DialogFilter>(*old_dialog_filter);
31839     new_dialog_filter->included_dialog_ids.push_back(get_input_dialog_id(dialog_id));
31840     td::remove_if(new_dialog_filter->excluded_dialog_ids,
31841                   [dialog_id](InputDialogId input_dialog_id) { return dialog_id == input_dialog_id.get_dialog_id(); });
31842 
31843     auto status = new_dialog_filter->check_limits();
31844     if (status.is_error()) {
31845       return promise.set_error(std::move(status));
31846     }
31847     sort_dialog_filter_input_dialog_ids(new_dialog_filter.get(), "add_dialog_to_list");
31848 
31849     edit_dialog_filter(std::move(new_dialog_filter), "add_dialog_to_list");
31850     save_dialog_filters();
31851     send_update_chat_filters();
31852 
31853     if (dialog_id.get_type() != DialogType::SecretChat) {
31854       synchronize_dialog_filters();
31855     }
31856 
31857     return promise.set_value(Unit());
31858   }
31859 
31860   CHECK(dialog_list_id.is_folder());
31861   auto folder_id = dialog_list_id.get_folder_id();
31862   if (d->folder_id == folder_id) {
31863     return promise.set_value(Unit());
31864   }
31865 
31866   if (folder_id == FolderId::archive() &&
31867       (dialog_id == get_my_dialog_id() ||
31868        dialog_id == DialogId(ContactsManager::get_service_notifications_user_id()))) {
31869     return promise.set_error(Status::Error(400, "Chat can't be archived"));
31870   }
31871 
31872   set_dialog_folder_id(d, folder_id);
31873 
31874   if (dialog_id.get_type() != DialogType::SecretChat) {
31875     set_dialog_folder_id_on_server(dialog_id, false);
31876   }
31877   promise.set_value(Unit());
31878 }
31879 
31880 class MessagesManager::SetDialogFolderIdOnServerLogEvent {
31881  public:
31882   DialogId dialog_id_;
31883   FolderId folder_id_;
31884 
31885   template <class StorerT>
store(StorerT & storer) const31886   void store(StorerT &storer) const {
31887     td::store(dialog_id_, storer);
31888     td::store(folder_id_, storer);
31889   }
31890 
31891   template <class ParserT>
parse(ParserT & parser)31892   void parse(ParserT &parser) {
31893     td::parse(dialog_id_, parser);
31894     td::parse(folder_id_, parser);
31895   }
31896 };
31897 
set_dialog_folder_id_on_server(DialogId dialog_id,bool from_binlog)31898 void MessagesManager::set_dialog_folder_id_on_server(DialogId dialog_id, bool from_binlog) {
31899   auto d = get_dialog(dialog_id);
31900   CHECK(d != nullptr);
31901 
31902   if (!from_binlog && G()->parameters().use_message_db) {
31903     SetDialogFolderIdOnServerLogEvent log_event;
31904     log_event.dialog_id_ = dialog_id;
31905     log_event.folder_id_ = d->folder_id;
31906     add_log_event(d->set_folder_id_log_event_id, get_log_event_storer(log_event),
31907                   LogEvent::HandlerType::SetDialogFolderIdOnServer, "set chat folder");
31908   }
31909 
31910   Promise<> promise;
31911   if (d->set_folder_id_log_event_id.log_event_id != 0) {
31912     d->set_folder_id_log_event_id.generation++;
31913     promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_id,
31914                                       generation = d->set_folder_id_log_event_id.generation](Result<Unit> result) {
31915       if (!G()->close_flag()) {
31916         send_closure(actor_id, &MessagesManager::on_updated_dialog_folder_id, dialog_id, generation);
31917       }
31918     });
31919   }
31920 
31921   // TODO do not send two queries simultaneously or use SequenceDispatcher
31922   td_->create_handler<EditPeerFoldersQuery>(std::move(promise))->send(dialog_id, d->folder_id);
31923 }
31924 
on_updated_dialog_folder_id(DialogId dialog_id,uint64 generation)31925 void MessagesManager::on_updated_dialog_folder_id(DialogId dialog_id, uint64 generation) {
31926   auto d = get_dialog(dialog_id);
31927   CHECK(d != nullptr);
31928   delete_log_event(d->set_folder_id_log_event_id, generation, "set chat folder");
31929 }
31930 
set_dialog_photo(DialogId dialog_id,const tl_object_ptr<td_api::InputChatPhoto> & input_photo,Promise<Unit> && promise)31931 void MessagesManager::set_dialog_photo(DialogId dialog_id, const tl_object_ptr<td_api::InputChatPhoto> &input_photo,
31932                                        Promise<Unit> &&promise) {
31933   LOG(INFO) << "Receive setChatPhoto request to change photo of " << dialog_id;
31934 
31935   if (!have_dialog_force(dialog_id, "set_dialog_photo")) {
31936     return promise.set_error(Status::Error(400, "Chat not found"));
31937   }
31938 
31939   switch (dialog_id.get_type()) {
31940     case DialogType::User:
31941       return promise.set_error(Status::Error(400, "Can't change private chat photo"));
31942     case DialogType::Chat: {
31943       auto chat_id = dialog_id.get_chat_id();
31944       auto status = td_->contacts_manager_->get_chat_permissions(chat_id);
31945       if (!status.can_change_info_and_settings() ||
31946           (td_->auth_manager_->is_bot() && !td_->contacts_manager_->is_appointed_chat_administrator(chat_id))) {
31947         return promise.set_error(Status::Error(400, "Not enough rights to change chat photo"));
31948       }
31949       break;
31950     }
31951     case DialogType::Channel: {
31952       auto status = td_->contacts_manager_->get_channel_permissions(dialog_id.get_channel_id());
31953       if (!status.can_change_info_and_settings()) {
31954         return promise.set_error(Status::Error(400, "Not enough rights to change chat photo"));
31955       }
31956       break;
31957     }
31958     case DialogType::SecretChat:
31959       return promise.set_error(Status::Error(400, "Can't change secret chat photo"));
31960     case DialogType::None:
31961     default:
31962       UNREACHABLE();
31963   }
31964 
31965   const td_api::object_ptr<td_api::InputFile> *input_file = nullptr;
31966   double main_frame_timestamp = 0.0;
31967   bool is_animation = false;
31968   if (input_photo != nullptr) {
31969     switch (input_photo->get_id()) {
31970       case td_api::inputChatPhotoPrevious::ID: {
31971         auto photo = static_cast<const td_api::inputChatPhotoPrevious *>(input_photo.get());
31972         auto file_id = td_->contacts_manager_->get_profile_photo_file_id(photo->chat_photo_id_);
31973         if (!file_id.is_valid()) {
31974           return promise.set_error(Status::Error(400, "Unknown profile photo ID specified"));
31975         }
31976 
31977         auto file_view = td_->file_manager_->get_file_view(file_id);
31978         auto input_chat_photo =
31979             make_tl_object<telegram_api::inputChatPhoto>(file_view.main_remote_location().as_input_photo());
31980         send_edit_dialog_photo_query(dialog_id, file_id, std::move(input_chat_photo), std::move(promise));
31981         return;
31982       }
31983       case td_api::inputChatPhotoStatic::ID: {
31984         auto photo = static_cast<const td_api::inputChatPhotoStatic *>(input_photo.get());
31985         input_file = &photo->photo_;
31986         break;
31987       }
31988       case td_api::inputChatPhotoAnimation::ID: {
31989         auto photo = static_cast<const td_api::inputChatPhotoAnimation *>(input_photo.get());
31990         input_file = &photo->animation_;
31991         main_frame_timestamp = photo->main_frame_timestamp_;
31992         is_animation = true;
31993         break;
31994       }
31995       default:
31996         UNREACHABLE();
31997         break;
31998     }
31999   }
32000   if (input_file == nullptr) {
32001     send_edit_dialog_photo_query(dialog_id, FileId(), make_tl_object<telegram_api::inputChatPhotoEmpty>(),
32002                                  std::move(promise));
32003     return;
32004   }
32005 
32006   const double MAX_ANIMATION_DURATION = 10.0;
32007   if (main_frame_timestamp < 0.0 || main_frame_timestamp > MAX_ANIMATION_DURATION) {
32008     return promise.set_error(Status::Error(400, "Wrong main frame timestamp specified"));
32009   }
32010 
32011   auto file_type = is_animation ? FileType::Animation : FileType::Photo;
32012   auto r_file_id = td_->file_manager_->get_input_file_id(file_type, *input_file, dialog_id, true, false);
32013   if (r_file_id.is_error()) {
32014     // TODO promise.set_error(std::move(status));
32015     return promise.set_error(Status::Error(400, r_file_id.error().message()));
32016   }
32017   FileId file_id = r_file_id.ok();
32018   if (!file_id.is_valid()) {
32019     send_edit_dialog_photo_query(dialog_id, FileId(), make_tl_object<telegram_api::inputChatPhotoEmpty>(),
32020                                  std::move(promise));
32021     return;
32022   }
32023 
32024   upload_dialog_photo(dialog_id, td_->file_manager_->dup_file_id(file_id), is_animation, main_frame_timestamp, false,
32025                       std::move(promise));
32026 }
32027 
send_edit_dialog_photo_query(DialogId dialog_id,FileId file_id,tl_object_ptr<telegram_api::InputChatPhoto> && input_chat_photo,Promise<Unit> && promise)32028 void MessagesManager::send_edit_dialog_photo_query(DialogId dialog_id, FileId file_id,
32029                                                    tl_object_ptr<telegram_api::InputChatPhoto> &&input_chat_photo,
32030                                                    Promise<Unit> &&promise) {
32031   // TODO invoke after
32032   td_->create_handler<EditDialogPhotoQuery>(std::move(promise))->send(dialog_id, file_id, std::move(input_chat_photo));
32033 }
32034 
upload_dialog_photo(DialogId dialog_id,FileId file_id,bool is_animation,double main_frame_timestamp,bool is_reupload,Promise<Unit> && promise,vector<int> bad_parts)32035 void MessagesManager::upload_dialog_photo(DialogId dialog_id, FileId file_id, bool is_animation,
32036                                           double main_frame_timestamp, bool is_reupload, Promise<Unit> &&promise,
32037                                           vector<int> bad_parts) {
32038   CHECK(file_id.is_valid());
32039   LOG(INFO) << "Ask to upload chat photo " << file_id;
32040   CHECK(being_uploaded_dialog_photos_.find(file_id) == being_uploaded_dialog_photos_.end());
32041   being_uploaded_dialog_photos_.emplace(
32042       file_id, UploadedDialogPhotoInfo{dialog_id, main_frame_timestamp, is_animation, is_reupload, std::move(promise)});
32043   // TODO use force_reupload if is_reupload
32044   td_->file_manager_->resume_upload(file_id, std::move(bad_parts), upload_dialog_photo_callback_, 32, 0);
32045 }
32046 
set_dialog_title(DialogId dialog_id,const string & title,Promise<Unit> && promise)32047 void MessagesManager::set_dialog_title(DialogId dialog_id, const string &title, Promise<Unit> &&promise) {
32048   LOG(INFO) << "Receive setChatTitle request to change title of " << dialog_id << " to \"" << title << '"';
32049 
32050   if (!have_dialog_force(dialog_id, "set_dialog_title")) {
32051     return promise.set_error(Status::Error(400, "Chat not found"));
32052   }
32053 
32054   auto new_title = clean_name(title, MAX_TITLE_LENGTH);
32055   if (new_title.empty()) {
32056     return promise.set_error(Status::Error(400, "Title can't be empty"));
32057   }
32058 
32059   switch (dialog_id.get_type()) {
32060     case DialogType::User:
32061       return promise.set_error(Status::Error(400, "Can't change private chat title"));
32062     case DialogType::Chat: {
32063       auto chat_id = dialog_id.get_chat_id();
32064       auto status = td_->contacts_manager_->get_chat_permissions(chat_id);
32065       if (!status.can_change_info_and_settings() ||
32066           (td_->auth_manager_->is_bot() && !td_->contacts_manager_->is_appointed_chat_administrator(chat_id))) {
32067         return promise.set_error(Status::Error(400, "Not enough rights to change chat title"));
32068       }
32069       break;
32070     }
32071     case DialogType::Channel: {
32072       auto status = td_->contacts_manager_->get_channel_permissions(dialog_id.get_channel_id());
32073       if (!status.can_change_info_and_settings()) {
32074         return promise.set_error(Status::Error(400, "Not enough rights to change chat title"));
32075       }
32076       break;
32077     }
32078     case DialogType::SecretChat:
32079       return promise.set_error(Status::Error(400, "Can't change secret chat title"));
32080     case DialogType::None:
32081     default:
32082       UNREACHABLE();
32083   }
32084 
32085   // TODO this can be wrong if there were previous change title requests
32086   if (get_dialog_title(dialog_id) == new_title) {
32087     return promise.set_value(Unit());
32088   }
32089 
32090   // TODO invoke after
32091   td_->create_handler<EditDialogTitleQuery>(std::move(promise))->send(dialog_id, new_title);
32092 }
32093 
set_dialog_message_ttl_setting(DialogId dialog_id,int32 ttl,Promise<Unit> && promise)32094 void MessagesManager::set_dialog_message_ttl_setting(DialogId dialog_id, int32 ttl, Promise<Unit> &&promise) {
32095   if (ttl < 0) {
32096     return promise.set_error(Status::Error(400, "Message auto-delete time can't be negative"));
32097   }
32098 
32099   Dialog *d = get_dialog_force(dialog_id, "set_dialog_message_ttl_setting");
32100   if (d == nullptr) {
32101     return promise.set_error(Status::Error(400, "Chat not found"));
32102   }
32103   if (!have_input_peer(dialog_id, AccessRights::Write)) {
32104     return promise.set_error(Status::Error(400, "Have no write access to the chat"));
32105   }
32106 
32107   LOG(INFO) << "Begin to set message TTL in " << dialog_id << " to " << ttl;
32108 
32109   switch (dialog_id.get_type()) {
32110     case DialogType::User:
32111       if (dialog_id == get_my_dialog_id() ||
32112           dialog_id == DialogId(ContactsManager::get_service_notifications_user_id())) {
32113         return promise.set_error(Status::Error(400, "Message auto-delete time in the chat can't be changed"));
32114       }
32115       break;
32116     case DialogType::Chat: {
32117       auto chat_id = dialog_id.get_chat_id();
32118       auto status = td_->contacts_manager_->get_chat_permissions(chat_id);
32119       if (!status.can_delete_messages()) {
32120         return promise.set_error(
32121             Status::Error(400, "Not enough rights to change message auto-delete time in the chat"));
32122       }
32123       break;
32124     }
32125     case DialogType::Channel: {
32126       auto status = td_->contacts_manager_->get_channel_permissions(dialog_id.get_channel_id());
32127       if (!status.can_change_info_and_settings()) {
32128         return promise.set_error(
32129             Status::Error(400, "Not enough rights to change message auto-delete time in the chat"));
32130       }
32131       break;
32132     }
32133     case DialogType::SecretChat:
32134       break;
32135     case DialogType::None:
32136     default:
32137       UNREACHABLE();
32138   }
32139 
32140   if (dialog_id.get_type() != DialogType::SecretChat) {
32141     // TODO invoke after
32142     td_->create_handler<SetHistoryTtlQuery>(std::move(promise))->send(dialog_id, ttl);
32143   } else {
32144     bool need_update_dialog_pos = false;
32145     Message *m = get_message_to_send(d, MessageId(), MessageId(), MessageSendOptions(),
32146                                      create_chat_set_ttl_message_content(ttl), &need_update_dialog_pos);
32147 
32148     send_update_new_message(d, m);
32149     if (need_update_dialog_pos) {
32150       send_update_chat_last_message(d, "set_dialog_message_ttl_setting");
32151     }
32152 
32153     int64 random_id = begin_send_message(dialog_id, m);
32154 
32155     send_closure(td_->secret_chats_manager_, &SecretChatsManager::send_set_ttl_message, dialog_id.get_secret_chat_id(),
32156                  ttl, random_id, std::move(promise));
32157   }
32158 }
32159 
set_dialog_permissions(DialogId dialog_id,const td_api::object_ptr<td_api::chatPermissions> & permissions,Promise<Unit> && promise)32160 void MessagesManager::set_dialog_permissions(DialogId dialog_id,
32161                                              const td_api::object_ptr<td_api::chatPermissions> &permissions,
32162                                              Promise<Unit> &&promise) {
32163   if (!have_dialog_force(dialog_id, "set_dialog_permissions")) {
32164     return promise.set_error(Status::Error(400, "Chat not found"));
32165   }
32166   if (!have_input_peer(dialog_id, AccessRights::Write)) {
32167     return promise.set_error(Status::Error(400, "Can't access the chat"));
32168   }
32169 
32170   if (permissions == nullptr) {
32171     return promise.set_error(Status::Error(400, "New permissions must be non-empty"));
32172   }
32173 
32174   switch (dialog_id.get_type()) {
32175     case DialogType::User:
32176       return promise.set_error(Status::Error(400, "Can't change private chat permissions"));
32177     case DialogType::Chat: {
32178       auto chat_id = dialog_id.get_chat_id();
32179       auto status = td_->contacts_manager_->get_chat_permissions(chat_id);
32180       if (!status.can_restrict_members()) {
32181         return promise.set_error(Status::Error(400, "Not enough rights to change chat permissions"));
32182       }
32183       break;
32184     }
32185     case DialogType::Channel: {
32186       if (is_broadcast_channel(dialog_id)) {
32187         return promise.set_error(Status::Error(400, "Can't change channel chat permissions"));
32188       }
32189       auto status = td_->contacts_manager_->get_channel_permissions(dialog_id.get_channel_id());
32190       if (!status.can_restrict_members()) {
32191         return promise.set_error(Status::Error(400, "Not enough rights to change chat permissions"));
32192       }
32193       break;
32194     }
32195     case DialogType::SecretChat:
32196       return promise.set_error(Status::Error(400, "Can't change secret chat permissions"));
32197     case DialogType::None:
32198     default:
32199       UNREACHABLE();
32200   }
32201 
32202   auto new_permissions = get_restricted_rights(permissions);
32203 
32204   // TODO this can be wrong if there were previous change permissions requests
32205   if (get_dialog_default_permissions(dialog_id) == new_permissions) {
32206     return promise.set_value(Unit());
32207   }
32208 
32209   // TODO invoke after
32210   td_->create_handler<EditChatDefaultBannedRightsQuery>(std::move(promise))->send(dialog_id, new_permissions);
32211 }
32212 
toggle_dialog_has_protected_content(DialogId dialog_id,bool has_protected_content,Promise<Unit> && promise)32213 void MessagesManager::toggle_dialog_has_protected_content(DialogId dialog_id, bool has_protected_content,
32214                                                           Promise<Unit> &&promise) {
32215   if (!have_dialog_force(dialog_id, "toggle_dialog_has_protected_content")) {
32216     return promise.set_error(Status::Error(400, "Chat not found"));
32217   }
32218   if (!have_input_peer(dialog_id, AccessRights::Read)) {
32219     return promise.set_error(Status::Error(400, "Can't access the chat"));
32220   }
32221 
32222   switch (dialog_id.get_type()) {
32223     case DialogType::User:
32224     case DialogType::SecretChat:
32225       return promise.set_error(Status::Error(400, "Can't restrict saving content in the chat"));
32226     case DialogType::Chat: {
32227       auto chat_id = dialog_id.get_chat_id();
32228       auto status = td_->contacts_manager_->get_chat_status(chat_id);
32229       if (!status.is_creator()) {
32230         return promise.set_error(Status::Error(400, "Only owner can restrict saving content"));
32231       }
32232       break;
32233     }
32234     case DialogType::Channel: {
32235       auto status = td_->contacts_manager_->get_channel_status(dialog_id.get_channel_id());
32236       if (!status.is_creator()) {
32237         return promise.set_error(Status::Error(400, "Only owner can restrict saving content"));
32238       }
32239       break;
32240     }
32241     case DialogType::None:
32242     default:
32243       UNREACHABLE();
32244   }
32245 
32246   // TODO this can be wrong if there were previous toggle_dialog_has_protected_content requests
32247   if (get_dialog_has_protected_content(dialog_id) == has_protected_content) {
32248     return promise.set_value(Unit());
32249   }
32250 
32251   // TODO invoke after
32252   td_->create_handler<ToggleNoForwardsQuery>(std::move(promise))->send(dialog_id, has_protected_content);
32253 }
32254 
set_dialog_theme(DialogId dialog_id,const string & theme_name,Promise<Unit> && promise)32255 void MessagesManager::set_dialog_theme(DialogId dialog_id, const string &theme_name, Promise<Unit> &&promise) {
32256   auto d = get_dialog_force(dialog_id, "set_dialog_theme");
32257   if (d == nullptr) {
32258     return promise.set_error(Status::Error(400, "Chat not found"));
32259   }
32260   if (!have_input_peer(dialog_id, AccessRights::Write)) {
32261     return promise.set_error(Status::Error(400, "Can't access the chat"));
32262   }
32263 
32264   switch (dialog_id.get_type()) {
32265     case DialogType::User:
32266       break;
32267     case DialogType::Chat:
32268     case DialogType::Channel:
32269       return promise.set_error(Status::Error(400, "Can't change theme in the chat"));
32270     case DialogType::SecretChat: {
32271       auto user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id());
32272       if (!user_id.is_valid()) {
32273         return promise.set_error(Status::Error(400, "Can't access the user"));
32274       }
32275       dialog_id = DialogId(user_id);
32276       break;
32277     }
32278     case DialogType::None:
32279     default:
32280       UNREACHABLE();
32281   }
32282 
32283   // TODO this can be wrong if there were previous change theme requests
32284   if (d->theme_name == theme_name) {
32285     return promise.set_value(Unit());
32286   }
32287 
32288   // TODO invoke after
32289   td_->create_handler<SetChatThemeQuery>(std::move(promise))->send(dialog_id, theme_name);
32290 }
32291 
set_dialog_description(DialogId dialog_id,const string & description,Promise<Unit> && promise)32292 void MessagesManager::set_dialog_description(DialogId dialog_id, const string &description, Promise<Unit> &&promise) {
32293   LOG(INFO) << "Receive setChatDescription request to set description of " << dialog_id << " to \"" << description
32294             << '"';
32295 
32296   if (!have_dialog_force(dialog_id, "set_dialog_description")) {
32297     return promise.set_error(Status::Error(400, "Chat not found"));
32298   }
32299 
32300   switch (dialog_id.get_type()) {
32301     case DialogType::User:
32302       return promise.set_error(Status::Error(400, "Can't change private chat description"));
32303     case DialogType::Chat:
32304       return td_->contacts_manager_->set_chat_description(dialog_id.get_chat_id(), description, std::move(promise));
32305     case DialogType::Channel:
32306       return td_->contacts_manager_->set_channel_description(dialog_id.get_channel_id(), description,
32307                                                              std::move(promise));
32308     case DialogType::SecretChat:
32309       return promise.set_error(Status::Error(400, "Can't change secret chat description"));
32310     case DialogType::None:
32311     default:
32312       UNREACHABLE();
32313   }
32314 }
32315 
can_pin_messages(DialogId dialog_id) const32316 Status MessagesManager::can_pin_messages(DialogId dialog_id) const {
32317   switch (dialog_id.get_type()) {
32318     case DialogType::User:
32319       break;
32320     case DialogType::Chat: {
32321       auto chat_id = dialog_id.get_chat_id();
32322       auto status = td_->contacts_manager_->get_chat_permissions(chat_id);
32323       if (!status.can_pin_messages() ||
32324           (td_->auth_manager_->is_bot() && !td_->contacts_manager_->is_appointed_chat_administrator(chat_id))) {
32325         return Status::Error(400, "Not enough rights to manage pinned messages in the chat");
32326       }
32327       break;
32328     }
32329     case DialogType::Channel: {
32330       auto status = td_->contacts_manager_->get_channel_permissions(dialog_id.get_channel_id());
32331       bool can_pin = is_broadcast_channel(dialog_id) ? status.can_edit_messages() : status.can_pin_messages();
32332       if (!can_pin) {
32333         return Status::Error(400, "Not enough rights to manage pinned messages in the chat");
32334       }
32335       break;
32336     }
32337     case DialogType::SecretChat:
32338       return Status::Error(400, "Secret chats can't have pinned messages");
32339     case DialogType::None:
32340     default:
32341       UNREACHABLE();
32342   }
32343   if (!have_input_peer(dialog_id, AccessRights::Write)) {
32344     return Status::Error(400, "Not enough rights");
32345   }
32346 
32347   return Status::OK();
32348 }
32349 
pin_dialog_message(DialogId dialog_id,MessageId message_id,bool disable_notification,bool only_for_self,bool is_unpin,Promise<Unit> && promise)32350 void MessagesManager::pin_dialog_message(DialogId dialog_id, MessageId message_id, bool disable_notification,
32351                                          bool only_for_self, bool is_unpin, Promise<Unit> &&promise) {
32352   auto d = get_dialog_force(dialog_id, "pin_dialog_message");
32353   if (d == nullptr) {
32354     return promise.set_error(Status::Error(400, "Chat not found"));
32355   }
32356   TRY_STATUS_PROMISE(promise, can_pin_messages(dialog_id));
32357 
32358   const Message *m = get_message_force(d, message_id, "pin_dialog_message");
32359   if (m == nullptr) {
32360     return promise.set_error(Status::Error(400, "Message not found"));
32361   }
32362   if (message_id.is_scheduled()) {
32363     return promise.set_error(Status::Error(400, "Scheduled message can't be pinned"));
32364   }
32365   if (!message_id.is_server()) {
32366     return promise.set_error(Status::Error(400, "Message can't be pinned"));
32367   }
32368 
32369   if (is_service_message_content(m->content->get_type())) {
32370     return promise.set_error(Status::Error(400, "A service message can't be pinned"));
32371   }
32372 
32373   if (only_for_self && dialog_id.get_type() != DialogType::User) {
32374     return promise.set_error(Status::Error(400, "Messages can't be pinned only for self in the chat"));
32375   }
32376 
32377   // TODO log event
32378   td_->create_handler<UpdateDialogPinnedMessageQuery>(std::move(promise))
32379       ->send(dialog_id, message_id, is_unpin, disable_notification, only_for_self);
32380 }
32381 
unpin_all_dialog_messages(DialogId dialog_id,Promise<Unit> && promise)32382 void MessagesManager::unpin_all_dialog_messages(DialogId dialog_id, Promise<Unit> &&promise) {
32383   auto d = get_dialog_force(dialog_id, "unpin_all_dialog_messages");
32384   if (d == nullptr) {
32385     return promise.set_error(Status::Error(400, "Chat not found"));
32386   }
32387   TRY_STATUS_PROMISE(promise, can_pin_messages(dialog_id));
32388 
32389   vector<MessageId> message_ids;
32390   find_messages(d->messages.get(), message_ids, [](const Message *m) { return m->is_pinned; });
32391 
32392   vector<int64> deleted_message_ids;
32393   for (auto message_id : message_ids) {
32394     auto m = get_message(d, message_id);
32395     CHECK(m != nullptr);
32396 
32397     m->is_pinned = false;
32398     send_closure(G()->td(), &Td::send_update,
32399                  make_tl_object<td_api::updateMessageIsPinned>(d->dialog_id.get(), m->message_id.get(), m->is_pinned));
32400     on_message_changed(d, m, true, "unpin_all_dialog_messages");
32401   }
32402 
32403   set_dialog_last_pinned_message_id(d, MessageId());
32404   if (d->message_count_by_index[message_search_filter_index(MessageSearchFilter::Pinned)] != 0) {
32405     d->message_count_by_index[message_search_filter_index(MessageSearchFilter::Pinned)] = 0;
32406     on_dialog_updated(dialog_id, "unpin_all_dialog_messages");
32407   }
32408 
32409   unpin_all_dialog_messages_on_server(dialog_id, 0, std::move(promise));
32410 }
32411 
32412 class MessagesManager::UnpinAllDialogMessagesOnServerLogEvent {
32413  public:
32414   DialogId dialog_id_;
32415 
32416   template <class StorerT>
store(StorerT & storer) const32417   void store(StorerT &storer) const {
32418     td::store(dialog_id_, storer);
32419   }
32420 
32421   template <class ParserT>
parse(ParserT & parser)32422   void parse(ParserT &parser) {
32423     td::parse(dialog_id_, parser);
32424   }
32425 };
32426 
save_unpin_all_dialog_messages_on_server_log_event(DialogId dialog_id)32427 uint64 MessagesManager::save_unpin_all_dialog_messages_on_server_log_event(DialogId dialog_id) {
32428   UnpinAllDialogMessagesOnServerLogEvent log_event{dialog_id};
32429   return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::UnpinAllDialogMessagesOnServer,
32430                     get_log_event_storer(log_event));
32431 }
32432 
unpin_all_dialog_messages_on_server(DialogId dialog_id,uint64 log_event_id,Promise<Unit> && promise)32433 void MessagesManager::unpin_all_dialog_messages_on_server(DialogId dialog_id, uint64 log_event_id,
32434                                                           Promise<Unit> &&promise) {
32435   if (log_event_id == 0 && G()->parameters().use_message_db) {
32436     log_event_id = save_unpin_all_dialog_messages_on_server_log_event(dialog_id);
32437   }
32438 
32439   AffectedHistoryQuery query = [td = td_](DialogId dialog_id, Promise<AffectedHistory> &&query_promise) {
32440     td->create_handler<UnpinAllMessagesQuery>(std::move(query_promise))->send(dialog_id);
32441   };
32442   run_affected_history_query_until_complete(dialog_id, std::move(query), true,
32443                                             get_erase_log_event_promise(log_event_id, std::move(promise)));
32444 }
32445 
treap_find_message(unique_ptr<Message> * v,MessageId message_id)32446 unique_ptr<MessagesManager::Message> *MessagesManager::treap_find_message(unique_ptr<Message> *v,
32447                                                                           MessageId message_id) {
32448   return const_cast<unique_ptr<Message> *>(treap_find_message(static_cast<const unique_ptr<Message> *>(v), message_id));
32449 }
32450 
treap_find_message(const unique_ptr<Message> * v,MessageId message_id)32451 const unique_ptr<MessagesManager::Message> *MessagesManager::treap_find_message(const unique_ptr<Message> *v,
32452                                                                                 MessageId message_id) {
32453   while (*v != nullptr) {
32454     if ((*v)->message_id < message_id) {
32455       v = &(*v)->right;
32456     } else if ((*v)->message_id > message_id) {
32457       v = &(*v)->left;
32458     } else {
32459       break;
32460     }
32461   }
32462   return v;
32463 }
32464 
treap_insert_message(unique_ptr<Message> * v,unique_ptr<Message> message)32465 MessagesManager::Message *MessagesManager::treap_insert_message(unique_ptr<Message> *v, unique_ptr<Message> message) {
32466   auto message_id = message->message_id;
32467   while (*v != nullptr && (*v)->random_y >= message->random_y) {
32468     if ((*v)->message_id < message_id) {
32469       v = &(*v)->right;
32470     } else if ((*v)->message_id == message_id) {
32471       UNREACHABLE();
32472     } else {
32473       v = &(*v)->left;
32474     }
32475   }
32476 
32477   unique_ptr<Message> *left = &message->left;
32478   unique_ptr<Message> *right = &message->right;
32479 
32480   unique_ptr<Message> cur = std::move(*v);
32481   while (cur != nullptr) {
32482     if (cur->message_id < message_id) {
32483       *left = std::move(cur);
32484       left = &((*left)->right);
32485       cur = std::move(*left);
32486     } else {
32487       *right = std::move(cur);
32488       right = &((*right)->left);
32489       cur = std::move(*right);
32490     }
32491   }
32492   CHECK(*left == nullptr);
32493   CHECK(*right == nullptr);
32494   *v = std::move(message);
32495   return v->get();
32496 }
32497 
treap_delete_message(unique_ptr<Message> * v)32498 unique_ptr<MessagesManager::Message> MessagesManager::treap_delete_message(unique_ptr<Message> *v) {
32499   unique_ptr<Message> result = std::move(*v);
32500   unique_ptr<Message> left = std::move(result->left);
32501   unique_ptr<Message> right = std::move(result->right);
32502 
32503   while (left != nullptr || right != nullptr) {
32504     if (left == nullptr || (right != nullptr && right->random_y > left->random_y)) {
32505       *v = std::move(right);
32506       v = &((*v)->left);
32507       right = std::move(*v);
32508     } else {
32509       *v = std::move(left);
32510       v = &((*v)->right);
32511       left = std::move(*v);
32512     }
32513   }
32514   CHECK(*v == nullptr);
32515 
32516   return result;
32517 }
32518 
get_message(Dialog * d,MessageId message_id)32519 MessagesManager::Message *MessagesManager::get_message(Dialog *d, MessageId message_id) {
32520   return const_cast<Message *>(get_message(static_cast<const Dialog *>(d), message_id));
32521 }
32522 
get_message(const Dialog * d,MessageId message_id)32523 const MessagesManager::Message *MessagesManager::get_message(const Dialog *d, MessageId message_id) {
32524   if (!message_id.is_valid() && !message_id.is_valid_scheduled()) {
32525     return nullptr;
32526   }
32527 
32528   CHECK(d != nullptr);
32529   bool is_scheduled = message_id.is_scheduled();
32530   if (is_scheduled && message_id.is_scheduled_server()) {
32531     auto server_message_id = message_id.get_scheduled_server_message_id();
32532     auto it = d->scheduled_message_date.find(server_message_id);
32533     if (it != d->scheduled_message_date.end()) {
32534       int32 date = it->second;
32535       message_id = MessageId(server_message_id, date);
32536       CHECK(message_id.is_scheduled_server());
32537     }
32538   }
32539   auto result = treap_find_message(is_scheduled ? &d->scheduled_messages : &d->messages, message_id)->get();
32540   if (result != nullptr && !is_scheduled) {
32541     result->last_access_date = G()->unix_time_cached();
32542   }
32543   LOG(INFO) << "Search for " << message_id << " in " << d->dialog_id << " found " << result;
32544   return result;
32545 }
32546 
get_message_force(Dialog * d,MessageId message_id,const char * source)32547 MessagesManager::Message *MessagesManager::get_message_force(Dialog *d, MessageId message_id, const char *source) {
32548   if (!message_id.is_valid() && !message_id.is_valid_scheduled()) {
32549     return nullptr;
32550   }
32551 
32552   auto result = get_message(d, message_id);
32553   if (result != nullptr) {
32554     return result;
32555   }
32556 
32557   if (!G()->parameters().use_message_db || message_id.is_yet_unsent()) {
32558     return nullptr;
32559   }
32560 
32561   if (d->deleted_message_ids.count(message_id)) {
32562     return nullptr;
32563   }
32564 
32565   if (message_id.is_scheduled()) {
32566     if (d->has_loaded_scheduled_messages_from_database) {
32567       return nullptr;
32568     }
32569     if (message_id.is_scheduled_server() &&
32570         d->deleted_scheduled_server_message_ids.count(message_id.get_scheduled_server_message_id())) {
32571       return nullptr;
32572     }
32573   }
32574 
32575   LOG(INFO) << "Trying to load " << FullMessageId{d->dialog_id, message_id} << " from database from " << source;
32576 
32577   auto r_value = G()->td_db()->get_messages_db_sync()->get_message({d->dialog_id, message_id});
32578   if (r_value.is_error()) {
32579     return nullptr;
32580   }
32581   return on_get_message_from_database(d, r_value.ok(), message_id.is_scheduled(), source);
32582 }
32583 
on_get_message_from_database(const MessagesDbMessage & message,bool is_scheduled,const char * source)32584 MessagesManager::Message *MessagesManager::on_get_message_from_database(const MessagesDbMessage &message,
32585                                                                         bool is_scheduled, const char *source) {
32586   return on_get_message_from_database(get_dialog_force(message.dialog_id, source), message.dialog_id,
32587                                       message.message_id, message.data, is_scheduled, source);
32588 }
32589 
on_get_message_from_database(Dialog * d,const MessagesDbDialogMessage & message,bool is_scheduled,const char * source)32590 MessagesManager::Message *MessagesManager::on_get_message_from_database(Dialog *d,
32591                                                                         const MessagesDbDialogMessage &message,
32592                                                                         bool is_scheduled, const char *source) {
32593   return on_get_message_from_database(d, d->dialog_id, message.message_id, message.data, is_scheduled, source);
32594 }
32595 
on_get_message_from_database(Dialog * d,DialogId dialog_id,MessageId expected_message_id,const BufferSlice & value,bool is_scheduled,const char * source)32596 MessagesManager::Message *MessagesManager::on_get_message_from_database(Dialog *d, DialogId dialog_id,
32597                                                                         MessageId expected_message_id,
32598                                                                         const BufferSlice &value, bool is_scheduled,
32599                                                                         const char *source) {
32600   if (value.empty()) {
32601     return nullptr;
32602   }
32603 
32604   auto m = parse_message(dialog_id, expected_message_id, value, is_scheduled);
32605   if (m == nullptr) {
32606     return nullptr;
32607   }
32608 
32609   if (d == nullptr) {
32610     LOG(ERROR) << "Can't find " << dialog_id << ", but have a message from it from " << source;
32611     if (!dialog_id.is_valid()) {
32612       LOG(ERROR) << "Got message in invalid " << dialog_id << " from " << source;
32613       return nullptr;
32614     }
32615 
32616     if (m->message_id.is_valid() && m->message_id.is_any_server() &&
32617         (dialog_id.get_type() == DialogType::User || dialog_id.get_type() == DialogType::Chat)) {
32618       get_message_from_server({dialog_id, m->message_id}, Auto(), "on_get_message_from_database 1");
32619     }
32620 
32621     force_create_dialog(dialog_id, source);
32622     d = get_dialog_force(dialog_id, source);
32623     CHECK(d != nullptr);
32624   }
32625 
32626   if (!have_input_peer(dialog_id, AccessRights::Read)) {
32627     return nullptr;
32628   }
32629 
32630   auto old_message = get_message(d, m->message_id);
32631   if (old_message != nullptr) {
32632     // data in the database is always outdated, so return a message from the memory
32633     if (dialog_id.get_type() == DialogType::SecretChat) {
32634       CHECK(!is_scheduled);
32635       // just in case restore random_id to message_id corespondence
32636       // can be needed if there was newer unloaded message with the same random_id
32637       add_random_id_to_message_id_correspondence(d, old_message->random_id, old_message->message_id);
32638     }
32639 
32640     if (old_message->notification_id.is_valid() && !is_scheduled) {
32641       add_notification_id_to_message_id_correspondence(d, old_message->notification_id, old_message->message_id);
32642     }
32643 
32644     return old_message;
32645   }
32646 
32647   Dependencies dependencies;
32648   add_message_dependencies(dependencies, m.get());
32649   if (!resolve_dependencies_force(td_, dependencies, "on_get_message_from_database") &&
32650       dialog_id.get_type() != DialogType::SecretChat) {
32651     get_message_from_server({dialog_id, m->message_id}, Auto(), "on_get_message_from_database 2");
32652   }
32653 
32654   m->have_previous = false;
32655   m->have_next = false;
32656   m->from_database = true;
32657   bool need_update = false;
32658   bool need_update_dialog_pos = false;
32659   auto result = add_message_to_dialog(d, std::move(m), false, &need_update, &need_update_dialog_pos, source);
32660   if (need_update_dialog_pos) {
32661     LOG(ERROR) << "Need update dialog pos after load " << (result == nullptr ? MessageId() : result->message_id)
32662                << " in " << dialog_id << " from " << source;
32663     send_update_chat_last_message(d, source);
32664   }
32665   return result;
32666 }
32667 
get_random_y(MessageId message_id)32668 int32 MessagesManager::get_random_y(MessageId message_id) {
32669   return static_cast<int32>(static_cast<uint32>(message_id.get() * 2101234567u));
32670 }
32671 
set_message_id(unique_ptr<Message> & message,MessageId message_id)32672 void MessagesManager::set_message_id(unique_ptr<Message> &message, MessageId message_id) {
32673   message->message_id = message_id;
32674   message->random_y = get_random_y(message_id);
32675 }
32676 
add_message_to_dialog(DialogId dialog_id,unique_ptr<Message> message,bool from_update,bool * need_update,bool * need_update_dialog_pos,const char * source)32677 MessagesManager::Message *MessagesManager::add_message_to_dialog(DialogId dialog_id, unique_ptr<Message> message,
32678                                                                  bool from_update, bool *need_update,
32679                                                                  bool *need_update_dialog_pos, const char *source) {
32680   CHECK(message != nullptr);
32681   CHECK(dialog_id.get_type() != DialogType::None);
32682   CHECK(need_update_dialog_pos != nullptr);
32683 
32684   MessageId message_id = message->message_id;
32685   if (!message_id.is_valid() && !message_id.is_valid_scheduled()) {
32686     LOG(ERROR) << "Receive " << message_id << " in " << dialog_id << " from " << source;
32687     debug_add_message_to_dialog_fail_reason_ = "invalid message identifier";
32688     return nullptr;
32689   }
32690 
32691   Dialog *d = get_dialog_force(dialog_id, source);
32692   if (d == nullptr) {
32693     if (from_update) {
32694       CHECK(!being_added_by_new_message_dialog_id_.is_valid());
32695       being_added_by_new_message_dialog_id_ = dialog_id;
32696     }
32697     d = add_dialog(dialog_id, "add_message_to_dialog");
32698     *need_update_dialog_pos = true;
32699     being_added_by_new_message_dialog_id_ = DialogId();
32700   } else {
32701     CHECK(d->dialog_id == dialog_id);
32702   }
32703   return add_message_to_dialog(d, std::move(message), from_update, need_update, need_update_dialog_pos, source);
32704 }
32705 
32706 // keep synced with add_scheduled_message_to_dialog
add_message_to_dialog(Dialog * d,unique_ptr<Message> message,bool from_update,bool * need_update,bool * need_update_dialog_pos,const char * source)32707 MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, unique_ptr<Message> message,
32708                                                                  bool from_update, bool *need_update,
32709                                                                  bool *need_update_dialog_pos, const char *source) {
32710   CHECK(message != nullptr);
32711   CHECK(d != nullptr);
32712   CHECK(need_update != nullptr);
32713   CHECK(need_update_dialog_pos != nullptr);
32714   CHECK(source != nullptr);
32715   debug_add_message_to_dialog_fail_reason_ = "success";
32716 
32717   auto debug_have_previous = message->have_previous;
32718   auto debug_have_next = message->have_next;
32719 
32720   DialogId dialog_id = d->dialog_id;
32721   MessageId message_id = message->message_id;
32722 
32723   if (!has_message_sender_user_id(dialog_id, message.get()) && !message->sender_dialog_id.is_valid()) {
32724     if (is_broadcast_channel(dialog_id)) {
32725       message->sender_dialog_id = dialog_id;
32726     } else {
32727       if (is_discussion_message(dialog_id, message.get())) {
32728         message->sender_dialog_id = message->forward_info->from_dialog_id;
32729       } else {
32730         LOG(ERROR) << "Failed to repair sender chat in " << message_id << " in " << dialog_id;
32731       }
32732     }
32733   }
32734   auto dialog_type = dialog_id.get_type();
32735   if (message->sender_user_id == ContactsManager::get_anonymous_bot_user_id() &&
32736       !message->sender_dialog_id.is_valid() && dialog_type == DialogType::Channel && !is_broadcast_channel(dialog_id)) {
32737     message->sender_user_id = UserId();
32738     message->sender_dialog_id = dialog_id;
32739   }
32740 
32741   if (!message->top_thread_message_id.is_valid() && !is_broadcast_channel(dialog_id) &&
32742       is_visible_message_reply_info(dialog_id, message.get()) && !message_id.is_scheduled()) {
32743     message->top_thread_message_id = message_id;
32744   }
32745 
32746   if (!message_id.is_scheduled() && message_id <= d->last_clear_history_message_id) {
32747     LOG(INFO) << "Skip adding cleared " << message_id << " to " << dialog_id << " from " << source;
32748     if (message->from_database) {
32749       delete_message_from_database(d, message_id, message.get(), true);
32750     }
32751     debug_add_message_to_dialog_fail_reason_ = "cleared full history";
32752     return nullptr;
32753   }
32754   if (d->deleted_message_ids.count(message->reply_to_message_id)) {
32755     // LOG(INFO) << "Remove reply to deleted " << message->reply_to_message_id << " in " << message_id << " from " << dialog_id << " from " << source;
32756     // we don't want to lose information that the message was a reply
32757     // message->reply_to_message_id = MessageId();
32758   }
32759 
32760   LOG(INFO) << "Adding " << message_id << " of type " << message->content->get_type() << " to " << dialog_id << " from "
32761             << source << ". Last new is " << d->last_new_message_id << ", last is " << d->last_message_id
32762             << ", from_update = " << from_update << ", have_previous = " << message->have_previous
32763             << ", have_next = " << message->have_next;
32764 
32765   if (!message_id.is_valid()) {
32766     if (message_id.is_valid_scheduled()) {
32767       return add_scheduled_message_to_dialog(d, std::move(message), from_update, need_update, source);
32768     }
32769     LOG(ERROR) << "Receive " << message_id << " in " << dialog_id << " from " << source;
32770     CHECK(!message->from_database);
32771     debug_add_message_to_dialog_fail_reason_ = "invalid message identifier";
32772     return nullptr;
32773   }
32774 
32775   if (*need_update) {
32776     CHECK(from_update);
32777   }
32778 
32779   if (d->deleted_message_ids.count(message_id)) {
32780     LOG(INFO) << "Skip adding deleted " << message_id << " to " << dialog_id << " from " << source;
32781     debug_add_message_to_dialog_fail_reason_ = "adding deleted message";
32782     return nullptr;
32783   }
32784 
32785   auto message_content_type = message->content->get_type();
32786   if (is_debug_message_op_enabled()) {
32787     d->debug_message_op.emplace_back(Dialog::MessageOp::Add, message_id, message_content_type, from_update,
32788                                      message->have_previous, message->have_next, source);
32789   }
32790 
32791   message->last_access_date = G()->unix_time_cached();
32792 
32793   if (from_update) {
32794     CHECK(message->have_next);
32795     CHECK(message->have_previous);
32796     if (message_id <= d->last_new_message_id && dialog_type != DialogType::Channel) {
32797       if (!G()->parameters().use_message_db) {
32798         if (td_->auth_manager_->is_bot() && Time::now() > start_time_ + 300 &&
32799             MessageId(ServerMessageId(100)) <= message_id && message_id <= MessageId(ServerMessageId(1000)) &&
32800             d->last_new_message_id >= MessageId(ServerMessageId(2147483000))) {
32801           LOG(FATAL) << "Force restart because of message_id overflow in " << dialog_id << " from "
32802                      << d->last_new_message_id << " to " << message_id;
32803         }
32804         LOG(ERROR) << "New " << message_id << " in " << dialog_id << " from " << source
32805                    << " has identifier less than last_new_message_id = " << d->last_new_message_id;
32806         dump_debug_message_op(d);
32807       }
32808     }
32809   }
32810 
32811   if (!from_update && !message->is_failed_to_send) {
32812     MessageId max_message_id;
32813     if (message_id.is_server()) {
32814       if (d->being_added_message_id.is_valid()) {
32815         // if a too new message not from update has failed to preload before being_added_message_id was set,
32816         // then it should fail to load even after it is set and last_new_message_id has changed
32817         max_message_id = d->being_updated_last_new_message_id;
32818       } else {
32819         max_message_id = d->last_new_message_id;
32820       }
32821     } else if (message_id.is_local()) {
32822       if (d->being_added_message_id.is_valid()) {
32823         max_message_id = d->being_updated_last_database_message_id;
32824       } else {
32825         max_message_id = d->last_database_message_id;
32826       }
32827     }
32828     if (max_message_id != MessageId() && message_id > max_message_id) {
32829       if (!message->from_database) {
32830         LOG(ERROR) << "Ignore " << message_id << " in " << dialog_id << " received not through update from " << source
32831                    << ". The maximum allowed is " << max_message_id << ", last is " << d->last_message_id
32832                    << ", being added message is " << d->being_added_message_id << ", channel difference "
32833                    << debug_channel_difference_dialog_ << " "
32834                    << to_string(get_message_object(dialog_id, message.get(), "add_message_to_dialog"));
32835         dump_debug_message_op(d, 3);
32836 
32837         if (need_channel_difference_to_add_message(dialog_id, nullptr)) {
32838           LOG(INFO) << "Schedule getDifference in " << dialog_id.get_channel_id();
32839           channel_get_difference_retry_timeout_.add_timeout_in(dialog_id.get(), 0.001);
32840         }
32841       } else {
32842         LOG(INFO) << "Ignore " << message_id << " in " << dialog_id << " received not through update from " << source;
32843       }
32844       debug_add_message_to_dialog_fail_reason_ = "too new message not from update";
32845       return nullptr;
32846     }
32847   }
32848   if ((message_id.is_server() || (message_id.is_local() && dialog_type == DialogType::SecretChat)) &&
32849       message_id <= d->max_unavailable_message_id) {
32850     LOG(INFO) << "Can't add an unavailable " << message_id << " to " << dialog_id << " from " << source;
32851     if (message->from_database) {
32852       delete_message_from_database(d, message_id, message.get(), true);
32853     }
32854     debug_add_message_to_dialog_fail_reason_ = "ignore unavailable message";
32855     return nullptr;
32856   }
32857 
32858   if (message_content_type == MessageContentType::ChatDeleteHistory) {
32859     {
32860       auto m = delete_message(d, message_id, true, need_update_dialog_pos, "message chat delete history");
32861       if (m != nullptr) {
32862         send_update_delete_messages(dialog_id, {m->message_id.get()}, true, false);
32863       }
32864     }
32865     int32 last_message_date = 0;
32866     if (d->last_message_id != MessageId()) {
32867       auto last_message = get_message(d, d->last_message_id);
32868       CHECK(last_message != nullptr);
32869       last_message_date = last_message->date - 1;
32870     } else {
32871       last_message_date = d->last_clear_history_date;
32872     }
32873     if (message->date > last_message_date) {
32874       set_dialog_last_clear_history_date(d, message->date, message_id, "update_last_clear_history_date");
32875       *need_update_dialog_pos = true;
32876     }
32877     LOG(INFO) << "Process MessageChatDeleteHistory in " << message_id << " in " << dialog_id << " with date "
32878               << message->date << " from " << source;
32879     if (message_id > d->max_unavailable_message_id) {
32880       set_dialog_max_unavailable_message_id(dialog_id, message_id, false, "message chat delete history");
32881     }
32882     CHECK(!message->from_database);
32883     debug_add_message_to_dialog_fail_reason_ = "skip adding MessageChatDeleteHistory";
32884     return nullptr;
32885   }
32886 
32887   if (*need_update && message_id <= d->last_new_message_id && !td_->auth_manager_->is_bot()) {
32888     *need_update = false;
32889   }
32890 
32891   if (message->reply_markup != nullptr &&
32892       (message->reply_markup->type == ReplyMarkup::Type::RemoveKeyboard ||
32893        (message->reply_markup->type == ReplyMarkup::Type::ForceReply && !message->reply_markup->is_personal)) &&
32894       !td_->auth_manager_->is_bot()) {
32895     if (from_update && message->reply_markup->is_personal) {  // if this keyboard is for us
32896       if (d->reply_markup_message_id != MessageId() && message_id > d->reply_markup_message_id) {
32897         const Message *old_message = get_message_force(d, d->reply_markup_message_id, "add_message_to_dialog 1");
32898         if (old_message == nullptr ||
32899             (old_message->sender_user_id.is_valid() && old_message->sender_user_id == message->sender_user_id)) {
32900           set_dialog_reply_markup(d, MessageId());
32901         }
32902       }
32903     }
32904     message->had_reply_markup = message->reply_markup->is_personal;
32905     message->reply_markup = nullptr;
32906   }
32907 
32908   bool auto_attach = message->have_previous && message->have_next &&
32909                      (from_update || message_id.is_local() || message_id.is_yet_unsent());
32910 
32911   {
32912     Message *m = message->from_database ? get_message(d, message_id)
32913                                         : get_message_force(d, message_id, "add_message_to_dialog 2");
32914     if (m != nullptr) {
32915       CHECK(m->message_id == message_id);
32916       CHECK(message->message_id == message_id);
32917       LOG(INFO) << "Adding already existing " << message_id << " in " << dialog_id << " from " << source;
32918       if (*need_update) {
32919         *need_update = false;
32920         if (!G()->parameters().use_message_db) {
32921           // can happen if the message is received first through getMessage in an unknown chat without
32922           // last_new_message_id and only after that received through getDifference or getChannelDifference
32923           if (d->last_new_message_id.is_valid()) {
32924             LOG(ERROR) << "Receive again " << (message->is_outgoing ? "outgoing" : "incoming")
32925                        << (message->forward_info == nullptr ? " not" : "") << " forwarded " << message_id
32926                        << " with content of type " << message_content_type << " in " << dialog_id << " from " << source
32927                        << ", current last new is " << d->last_new_message_id << ", last is " << d->last_message_id;
32928             dump_debug_message_op(d, 1);
32929           }
32930         }
32931       }
32932       if (auto_attach) {
32933         CHECK(message->have_previous);
32934         CHECK(message->have_next);
32935         message->have_previous = false;
32936         message->have_next = false;
32937       }
32938       if (!message->from_database && (from_update || message->edit_date >= m->edit_date)) {
32939         const int32 INDEX_MASK_MASK = ~message_search_filter_index_mask(MessageSearchFilter::UnreadMention);
32940         auto old_index_mask = get_message_index_mask(dialog_id, m) & INDEX_MASK_MASK;
32941         bool was_deleted = delete_active_live_location(dialog_id, m);
32942         auto old_file_ids = get_message_content_file_ids(m->content.get(), td_);
32943         bool need_send_update = update_message(d, m, std::move(message), need_update_dialog_pos, true);
32944         if (!need_send_update) {
32945           LOG(INFO) << message_id << " in " << dialog_id << " is not changed";
32946         }
32947         auto new_index_mask = get_message_index_mask(dialog_id, m) & INDEX_MASK_MASK;
32948         if (was_deleted) {
32949           try_add_active_live_location(dialog_id, m);
32950         }
32951         change_message_files(dialog_id, m, old_file_ids);
32952         if (need_send_update && m->notification_id.is_valid() && is_message_notification_active(d, m)) {
32953           auto &group_info = get_notification_group_info(d, m);
32954           if (group_info.group_id.is_valid()) {
32955             send_closure_later(G()->notification_manager(), &NotificationManager::edit_notification,
32956                                group_info.group_id, m->notification_id, create_new_message_notification(m->message_id));
32957           }
32958         }
32959         if (need_send_update && m->is_pinned && d->pinned_message_notification_message_id.is_valid() &&
32960             d->mention_notification_group.group_id.is_valid()) {
32961           auto pinned_message = get_message_force(d, d->pinned_message_notification_message_id, "after update_message");
32962           if (pinned_message != nullptr && pinned_message->notification_id.is_valid() &&
32963               is_message_notification_active(d, pinned_message) &&
32964               get_message_content_pinned_message_id(pinned_message->content.get()) == message_id) {
32965             send_closure_later(G()->notification_manager(), &NotificationManager::edit_notification,
32966                                d->mention_notification_group.group_id, pinned_message->notification_id,
32967                                create_new_message_notification(pinned_message->message_id));
32968           }
32969         }
32970         update_message_count_by_index(d, -1, old_index_mask & ~new_index_mask);
32971         update_message_count_by_index(d, +1, new_index_mask & ~old_index_mask);
32972       }
32973       return m;
32974     }
32975   }
32976 
32977   if (*need_update && !td_->auth_manager_->is_bot()) {
32978     if (message_content_type == MessageContentType::PinMessage) {
32979       if (is_dialog_pinned_message_notifications_disabled(d) ||
32980           !get_message_content_pinned_message_id(message->content.get()).is_valid()) {
32981         // treat message pin without pinned message as an ordinary message
32982         message->contains_mention = false;
32983       }
32984     } else if (message->contains_mention && is_dialog_mention_notifications_disabled(d)) {
32985       // disable mention notification
32986       message->is_mention_notification_disabled = true;
32987     }
32988   }
32989 
32990   if (message->contains_unread_mention && message_id <= d->last_read_all_mentions_message_id) {
32991     LOG(INFO) << "Ignore unread mention in " << message_id;
32992     message->contains_unread_mention = false;
32993     if (message->from_database) {
32994       on_message_changed(d, message.get(), false, "add already read mention message to dialog");
32995     }
32996   }
32997 
32998   if (*need_update && may_need_message_notification(d, message.get())) {
32999     // notification group must be created here because it may force adding new messages from database
33000     // in get_message_notification_group_force
33001     get_dialog_notification_group_id(d->dialog_id, get_notification_group_info(d, message.get()));
33002   }
33003   if (*need_update || (!d->last_new_message_id.is_valid() && !message_id.is_yet_unsent() && from_update)) {
33004     auto pinned_message_id = get_message_content_pinned_message_id(message->content.get());
33005     if (pinned_message_id.is_valid() && pinned_message_id < message_id &&
33006         have_message_force(d, pinned_message_id, "preload pinned message")) {
33007       LOG(INFO) << "Preloaded pinned " << pinned_message_id << " from database";
33008     }
33009 
33010     if (d->pinned_message_notification_message_id.is_valid() &&
33011         d->pinned_message_notification_message_id != message_id &&
33012         have_message_force(d, d->pinned_message_notification_message_id, "preload previously pinned message")) {
33013       LOG(INFO) << "Preloaded previously pinned " << d->pinned_message_notification_message_id << " from database";
33014     }
33015   }
33016   if (from_update && message->top_thread_message_id.is_valid() && message->top_thread_message_id != message_id &&
33017       message_id.is_server() && have_message_force(d, message->top_thread_message_id, "preload top reply message")) {
33018     LOG(INFO) << "Preloaded top thread " << message->top_thread_message_id << " from database";
33019 
33020     Message *top_m = get_message(d, message->top_thread_message_id);
33021     CHECK(top_m != nullptr);
33022     if (is_active_message_reply_info(dialog_id, top_m->reply_info) && is_discussion_message(dialog_id, top_m)) {
33023       FullMessageId top_full_message_id{top_m->forward_info->from_dialog_id, top_m->forward_info->from_message_id};
33024       if (have_message_force(top_full_message_id, "preload discussed message")) {
33025         LOG(INFO) << "Preloaded discussed " << top_full_message_id << " from database";
33026       }
33027     }
33028   }
33029 
33030   // there must be no two recursive calls to add_message_to_dialog
33031   LOG_CHECK(!d->being_added_message_id.is_valid())
33032       << d->dialog_id << " " << d->being_added_message_id << " " << message_id << " " << *need_update << " "
33033       << d->pinned_message_notification_message_id << " " << d->last_new_message_id << " " << source;
33034   LOG_CHECK(!d->being_deleted_message_id.is_valid())
33035       << d->being_deleted_message_id << " " << message_id << " " << source;
33036 
33037   d->being_added_message_id = message_id;
33038   d->being_updated_last_new_message_id = d->last_new_message_id;
33039   d->being_updated_last_database_message_id = d->last_database_message_id;
33040 
33041   if (d->new_secret_chat_notification_id.is_valid()) {
33042     remove_new_secret_chat_notification(d, true);
33043   }
33044 
33045   if (message->message_id > d->max_added_message_id) {
33046     d->max_added_message_id = message->message_id;
33047   }
33048 
33049   if (d->have_full_history && !message->from_database && !from_update && !message_id.is_local() &&
33050       !message_id.is_yet_unsent()) {
33051     LOG(ERROR) << "Have full history in " << dialog_id << ", but receive unknown " << message_id
33052                << " with content of type " << message_content_type << " from " << source << ". Last new is "
33053                << d->last_new_message_id << ", last is " << d->last_message_id << ", first database is "
33054                << d->first_database_message_id << ", last database is " << d->last_database_message_id
33055                << ", last read inbox is " << d->last_read_inbox_message_id << ", last read outbox is "
33056                << d->last_read_inbox_message_id << ", last read all mentions is "
33057                << d->last_read_all_mentions_message_id << ", max unavailable is " << d->max_unavailable_message_id
33058                << ", last assigned is " << d->last_assigned_message_id;
33059     d->have_full_history = false;
33060     on_dialog_updated(dialog_id, "drop have_full_history");
33061   }
33062 
33063   if (!d->is_opened && d->messages != nullptr && is_message_unload_enabled() && !d->has_unload_timeout) {
33064     LOG(INFO) << "Schedule unload of " << dialog_id;
33065     pending_unload_dialog_timeout_.add_timeout_in(dialog_id.get(), get_unload_dialog_delay());
33066     d->has_unload_timeout = true;
33067   }
33068 
33069   if (message->ttl > 0 && message->ttl_expires_at != 0) {
33070     auto now = Time::now();
33071     if (message->ttl_expires_at <= now) {
33072       if (dialog_type == DialogType::SecretChat) {
33073         LOG(INFO) << "Can't add " << message_id << " with expired TTL to " << dialog_id << " from " << source;
33074         delete_message_from_database(d, message_id, message.get(), true);
33075         debug_add_message_to_dialog_fail_reason_ = "delete expired by TTL message";
33076         d->being_added_message_id = MessageId();
33077         return nullptr;
33078       } else {
33079         on_message_ttl_expired_impl(d, message.get());
33080         message_content_type = message->content->get_type();
33081         if (message->from_database) {
33082           on_message_changed(d, message.get(), false, "add expired message to dialog");
33083         }
33084       }
33085     } else {
33086       ttl_register_message(dialog_id, message.get(), now);
33087     }
33088   }
33089   if (message->ttl_period > 0) {
33090     CHECK(dialog_type != DialogType::SecretChat);
33091     auto server_time = G()->server_time();
33092     if (message->date + message->ttl_period <= server_time) {
33093       LOG(INFO) << "Can't add " << message_id << " with expired TTL period to " << dialog_id << " from " << source;
33094       delete_message_from_database(d, message_id, message.get(), true);
33095       debug_add_message_to_dialog_fail_reason_ = "delete expired by TTL period message";
33096       d->being_added_message_id = MessageId();
33097       return nullptr;
33098     } else {
33099       ttl_period_register_message(dialog_id, message.get(), server_time);
33100     }
33101   }
33102 
33103   if (message->from_database && !message->are_media_timestamp_entities_found) {
33104     auto text = get_message_content_text_mutable(message->content.get());
33105     if (text != nullptr) {
33106       fix_formatted_text(text->text, text->entities, true, true, true, false, false).ensure();
33107       // always call to save are_media_timestamp_entities_found flag
33108       on_message_changed(d, message.get(), false, "save media timestamp entities");
33109     }
33110   }
33111   message->are_media_timestamp_entities_found = true;
33112 
33113   LOG(INFO) << "Adding not found " << message_id << " to " << dialog_id << " from " << source;
33114   if (d->is_empty) {
33115     d->is_empty = false;
33116     *need_update_dialog_pos = true;
33117   }
33118 
33119   if (dialog_type == DialogType::Channel && !message->contains_unread_mention) {
33120     auto channel_read_media_period =
33121         G()->shared_config().get_option_integer("channels_read_media_period", (G()->is_test_dc() ? 300 : 7 * 86400));
33122     if (message->date < G()->unix_time_cached() - channel_read_media_period) {
33123       update_opened_message_content(message->content.get());
33124     }
33125   }
33126 
33127   if (G()->parameters().use_file_db && message_id.is_yet_unsent() && !message->via_bot_user_id.is_valid() &&
33128       !message->hide_via_bot && !message->is_copy) {
33129     auto queue_id = get_sequence_dispatcher_id(dialog_id, message_content_type);
33130     if (queue_id & 1) {
33131       LOG(INFO) << "Add " << message_id << " from " << source << " to queue " << queue_id;
33132       yet_unsent_media_queues_[queue_id][message_id];  // reserve place for promise
33133       if (!td_->auth_manager_->is_bot()) {
33134         pending_send_dialog_action_timeout_.add_timeout_in(dialog_id.get(), 1.0);
33135       }
33136     }
33137   }
33138 
33139   if (!(d->have_full_history && auto_attach) && d->last_message_id.is_valid() &&
33140       d->last_message_id < MessageId(ServerMessageId(1)) && message_id >= MessageId(ServerMessageId(1))) {
33141     set_dialog_last_message_id(d, MessageId(), "add_message_to_dialog");
33142 
33143     set_dialog_first_database_message_id(d, MessageId(), "add_message_to_dialog");
33144     set_dialog_last_database_message_id(d, MessageId(), source);
33145     d->have_full_history = false;
33146     invalidate_message_indexes(d);
33147     d->local_unread_count = 0;  // read all local messages. They will not be reachable anymore
33148 
33149     on_dialog_updated(dialog_id, "add gap to dialog");
33150 
33151     send_update_chat_last_message(d, "add gap to dialog");
33152     *need_update_dialog_pos = false;
33153   }
33154 
33155   if (from_update && message_id > d->last_new_message_id && !message_id.is_yet_unsent()) {
33156     if (dialog_type == DialogType::SecretChat || message_id.is_server()) {
33157       // can delete messages, therefore must be called before message attaching/adding
33158       set_dialog_last_new_message_id(d, message_id, "add_message_to_dialog");
33159     }
33160   }
33161 
33162   bool is_attached = false;
33163   if (auto_attach) {
33164     auto it = MessagesIterator(d, message_id);
33165     Message *previous_message = *it;
33166     if (previous_message != nullptr) {
33167       auto previous_message_id = previous_message->message_id;
33168       CHECK(previous_message_id < message_id);
33169       if (previous_message->have_next || (d->last_message_id.is_valid() && previous_message_id >= d->last_message_id)) {
33170         if (message_id.is_server() && previous_message_id.is_server() && previous_message->have_next) {
33171           ++it;
33172           auto next_message = *it;
33173           if (next_message != nullptr) {
33174             if (next_message->message_id.is_server()) {
33175               LOG(ERROR) << "Attach " << message_id << " from " << source << " before " << next_message->message_id
33176                          << " and after " << previous_message_id << " in " << dialog_id;
33177               dump_debug_message_op(d);
33178             }
33179           } else {
33180             LOG(ERROR) << "Have_next is true, but there is no next message after " << previous_message_id << " from "
33181                        << source << " in " << dialog_id;
33182             dump_debug_message_op(d);
33183           }
33184         }
33185 
33186         LOG(INFO) << "Attach " << message_id << " to the previous " << previous_message_id << " in " << dialog_id;
33187         message->have_previous = true;
33188         message->have_next = previous_message->have_next;
33189         previous_message->have_next = true;
33190         is_attached = true;
33191       }
33192     }
33193     if (!is_attached && !message_id.is_yet_unsent()) {
33194       // message may be attached to the next message if there is no previous message
33195       Message *cur = d->messages.get();
33196       Message *next_message = nullptr;
33197       while (cur != nullptr) {
33198         if (cur->message_id < message_id) {
33199           cur = cur->right.get();
33200         } else {
33201           next_message = cur;
33202           cur = cur->left.get();
33203         }
33204       }
33205       if (next_message != nullptr) {
33206         CHECK(!next_message->have_previous);
33207         LOG(INFO) << "Attach " << message_id << " to the next " << next_message->message_id << " in " << dialog_id;
33208         if (from_update && !next_message->message_id.is_yet_unsent()) {
33209           LOG(ERROR) << "Attach " << message_id << " from " << source << " to the next " << next_message->message_id
33210                      << " in " << dialog_id;
33211         }
33212         message->have_next = true;
33213         message->have_previous = next_message->have_previous;
33214         next_message->have_previous = true;
33215         is_attached = true;
33216       }
33217     }
33218     if (!is_attached) {
33219       LOG(INFO) << "Can't auto-attach " << message_id << " in " << dialog_id;
33220       message->have_previous = false;
33221       message->have_next = false;
33222     }
33223   }
33224 
33225   if (!td_->auth_manager_->is_bot()) {
33226     if (*need_update) {
33227       // notification must be added before updating unread_count to have correct total notification count
33228       // in get_message_notification_group_force
33229       add_new_message_notification(d, message.get(), false);
33230     } else {
33231       if (message->from_database && message->notification_id.is_valid() &&
33232           is_from_mention_notification_group(d, message.get()) && is_message_notification_active(d, message.get()) &&
33233           is_dialog_mention_notifications_disabled(d) && message_id != d->pinned_message_notification_message_id) {
33234         auto notification_id = message->notification_id;
33235         VLOG(notifications) << "Remove mention " << notification_id << " in " << message_id << " in " << dialog_id;
33236         message->notification_id = NotificationId();
33237         if (d->mention_notification_group.last_notification_id == notification_id) {
33238           // last notification is deleted, need to find new last notification
33239           fix_dialog_last_notification_id(d, true, message_id);
33240         }
33241 
33242         send_closure_later(G()->notification_manager(), &NotificationManager::remove_notification,
33243                            d->mention_notification_group.group_id, notification_id, false, false, Promise<Unit>(),
33244                            "remove disabled mention notification");
33245 
33246         on_message_changed(d, message.get(), false, "remove_mention_notification");
33247       }
33248     }
33249   }
33250 
33251   if (*need_update && message_id > d->last_read_inbox_message_id && !td_->auth_manager_->is_bot()) {
33252     if (has_incoming_notification(dialog_id, message.get())) {
33253       int32 server_unread_count = d->server_unread_count;
33254       int32 local_unread_count = d->local_unread_count;
33255       if (message_id.is_server()) {
33256         server_unread_count++;
33257       } else {
33258         local_unread_count++;
33259       }
33260       set_dialog_last_read_inbox_message_id(d, MessageId::min(), server_unread_count, local_unread_count, false,
33261                                             source);
33262     } else {
33263       // if non-scheduled outgoing message has identifier one greater than last_read_inbox_message_id,
33264       // then definitely there are no unread incoming messages before it
33265       if (message_id.is_server() && d->last_read_inbox_message_id.is_valid() &&
33266           d->last_read_inbox_message_id.is_server() &&
33267           message_id.get_server_message_id().get() == d->last_read_inbox_message_id.get_server_message_id().get() + 1) {
33268         read_history_inbox(dialog_id, message_id, 0, "add_message_to_dialog");
33269       }
33270     }
33271   }
33272   if (*need_update && message->contains_unread_mention) {
33273     set_dialog_unread_mention_count(d, d->unread_mention_count + 1);
33274     send_update_chat_unread_mention_count(d);
33275   }
33276   if (*need_update) {
33277     update_message_count_by_index(d, +1, message.get());
33278   }
33279   if (auto_attach && message_id > d->last_message_id && message_id >= d->last_new_message_id) {
33280     set_dialog_last_message_id(d, message_id, "add_message_to_dialog");
33281     *need_update_dialog_pos = true;
33282   }
33283   if (auto_attach && !message_id.is_yet_unsent() && message_id >= d->last_new_message_id &&
33284       (d->last_new_message_id.is_valid() ||
33285        (message_id.is_local() && d->last_message_id.is_valid() &&
33286         (message_id >= d->last_message_id ||
33287          (d->last_database_message_id.is_valid() && message_id > d->last_database_message_id))))) {
33288     CHECK(message_id <= d->last_message_id);
33289     if (message_id > d->last_database_message_id) {
33290       set_dialog_last_database_message_id(d, message_id, "add_message_to_dialog");
33291       if (!d->first_database_message_id.is_valid()) {
33292         set_dialog_first_database_message_id(d, message_id, "add_message_to_dialog");
33293         try_restore_dialog_reply_markup(d, message.get());
33294       }
33295     }
33296   }
33297 
33298   const Message *m = message.get();
33299   if (m->message_id.is_yet_unsent() && m->reply_to_message_id.is_valid() && !m->reply_to_message_id.is_yet_unsent()) {
33300     replied_by_yet_unsent_messages_[FullMessageId{dialog_id, m->reply_to_message_id}]++;
33301   }
33302 
33303   if (!m->from_database && !m->message_id.is_yet_unsent()) {
33304     add_message_to_database(d, m, "add_message_to_dialog");
33305   }
33306 
33307   if (from_update && dialog_type == DialogType::Channel) {
33308     auto now = max(G()->unix_time_cached(), m->date);
33309     if (m->date < now - 2 * 86400 && Slice(source) == Slice("updateNewChannelMessage")) {
33310       // if the message is pretty old, we might have missed the update that the message has already been read
33311       repair_channel_server_unread_count(d);
33312     }
33313     if (m->date + 3600 >= now && m->is_outgoing) {
33314       auto channel_id = dialog_id.get_channel_id();
33315       auto slow_mode_delay = td_->contacts_manager_->get_channel_slow_mode_delay(channel_id);
33316       auto status = td_->contacts_manager_->get_channel_status(dialog_id.get_channel_id());
33317       if (m->date + slow_mode_delay > now && !status.is_administrator()) {
33318         td_->contacts_manager_->on_update_channel_slow_mode_next_send_date(channel_id, m->date + slow_mode_delay);
33319       }
33320     }
33321     if (m->date > now - 14 * 86400) {
33322       td_->contacts_manager_->remove_inactive_channel(dialog_id.get_channel_id());
33323     }
33324   }
33325 
33326   if (!is_attached && !m->have_next && !m->have_previous) {
33327     MessagesIterator it(d, m->message_id);
33328     if (*it != nullptr && (*it)->have_next) {
33329       // need to drop a connection between messages
33330       auto previous_message = *it;
33331       ++it;
33332       auto next_message = *it;
33333       if (next_message != nullptr) {
33334         if (next_message->message_id.is_server() &&
33335             !(td_->auth_manager_->is_bot() && Slice(source) == Slice("GetChannelMessagesQuery"))) {
33336           LOG(ERROR) << "Can't attach " << m->message_id << " from " << source << " from "
33337                      << (m->from_database ? "database" : "server") << " before " << next_message->message_id
33338                      << " and after " << previous_message->message_id << " in " << dialog_id;
33339           dump_debug_message_op(d);
33340         }
33341 
33342         next_message->have_previous = false;
33343         previous_message->have_next = false;
33344       } else {
33345         LOG(ERROR) << "Have_next is true, but there is no next message after " << previous_message->message_id
33346                    << " from " << source << " in " << dialog_id;
33347         dump_debug_message_op(d);
33348       }
33349     }
33350   }
33351 
33352   if (message_content_type == MessageContentType::ContactRegistered && !d->has_contact_registered_message) {
33353     d->has_contact_registered_message = true;
33354     on_dialog_updated(dialog_id, "update_has_contact_registered_message");
33355   }
33356 
33357   reget_message_from_server_if_needed(dialog_id, m);
33358 
33359   add_message_file_sources(dialog_id, m);
33360 
33361   register_message_content(td_, m->content.get(), {dialog_id, m->message_id}, "add_message_to_dialog");
33362 
33363   register_message_reply(d, m);
33364 
33365   if (*need_update && m->message_id.is_server() && message_content_type == MessageContentType::PinMessage) {
33366     auto pinned_message_id = get_message_content_pinned_message_id(m->content.get());
33367     if (d->is_last_pinned_message_id_inited && pinned_message_id > d->last_pinned_message_id) {
33368       set_dialog_last_pinned_message_id(d, pinned_message_id);
33369     }
33370   }
33371   if (*need_update && m->message_id.is_server() && message_content_type == MessageContentType::ChatSetTheme) {
33372     set_dialog_theme_name(d, get_message_content_theme_name(m->content.get()));
33373   }
33374 
33375   if (from_update) {
33376     speculatively_update_active_group_call_id(d, m);
33377     speculatively_update_channel_participants(dialog_id, m);
33378     update_sent_message_contents(dialog_id, m);
33379     update_used_hashtags(dialog_id, m);
33380     update_top_dialogs(dialog_id, m);
33381     cancel_dialog_action(dialog_id, m);
33382     update_has_outgoing_messages(dialog_id, m);
33383 
33384     if (!td_->auth_manager_->is_bot() && d->messages == nullptr && !m->is_outgoing && dialog_id != get_my_dialog_id()) {
33385       switch (dialog_type) {
33386         case DialogType::User:
33387           td_->contacts_manager_->invalidate_user_full(dialog_id.get_user_id());
33388           td_->contacts_manager_->reload_user_full(dialog_id.get_user_id());
33389           break;
33390         case DialogType::Chat:
33391         case DialogType::Channel:
33392           // nothing to do
33393           break;
33394         case DialogType::SecretChat: {
33395           auto user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id());
33396           if (user_id.is_valid()) {
33397             td_->contacts_manager_->invalidate_user_full(user_id);
33398             td_->contacts_manager_->reload_user_full(user_id);
33399           }
33400           break;
33401         }
33402         case DialogType::None:
33403         default:
33404           UNREACHABLE();
33405       }
33406     }
33407   }
33408 
33409   Message *result_message = treap_insert_message(&d->messages, std::move(message));
33410   CHECK(result_message != nullptr);
33411   CHECK(result_message == m);
33412   CHECK(d->messages != nullptr);
33413 
33414   if (!is_attached) {
33415     if (m->have_next) {
33416       LOG_CHECK(!m->have_previous) << auto_attach << " " << dialog_id << " " << m->message_id << " " << from_update
33417                                    << " " << *need_update << " " << d->being_updated_last_new_message_id << " "
33418                                    << d->last_new_message_id << " " << d->being_updated_last_database_message_id << " "
33419                                    << d->last_database_message_id << " " << debug_have_previous << " "
33420                                    << debug_have_next << " " << source;
33421       attach_message_to_next(d, m->message_id, source);
33422     } else if (m->have_previous) {
33423       attach_message_to_previous(d, m->message_id, source);
33424     }
33425   }
33426 
33427   if (m->message_id.is_yet_unsent() && m->top_thread_message_id.is_valid()) {
33428     auto is_inserted = d->yet_unsent_thread_message_ids[m->top_thread_message_id].insert(m->message_id).second;
33429     CHECK(is_inserted);
33430   }
33431 
33432   switch (dialog_type) {
33433     case DialogType::User:
33434     case DialogType::Chat:
33435       if (m->message_id.is_server()) {
33436         message_id_to_dialog_id_[m->message_id] = dialog_id;
33437       }
33438       break;
33439     case DialogType::Channel:
33440       // nothing to do
33441       break;
33442     case DialogType::SecretChat:
33443       add_random_id_to_message_id_correspondence(d, m->random_id, m->message_id);
33444       break;
33445     case DialogType::None:
33446     default:
33447       UNREACHABLE();
33448   }
33449 
33450   if (m->notification_id.is_valid()) {
33451     add_notification_id_to_message_id_correspondence(d, m->notification_id, m->message_id);
33452   }
33453 
33454   try_add_bot_command_message_id(dialog_id, m);
33455 
33456   // must be called after the message is added to correctly update replies
33457   update_message_max_reply_media_timestamp(d, result_message, false);
33458   update_message_max_own_media_timestamp(d, result_message);
33459 
33460   result_message->debug_source = source;
33461   d->being_added_message_id = MessageId();
33462 
33463   if (!td_->auth_manager_->is_bot() && from_update && d->reply_markup_message_id != MessageId()) {
33464     auto deleted_user_id = get_message_content_deleted_user_id(m->content.get());
33465     if (deleted_user_id.is_valid()) {  // do not check for is_user_bot to allow deleted bots
33466       const Message *old_message = get_message_force(d, d->reply_markup_message_id, "add_message_to_dialog 3");
33467       if (old_message == nullptr || old_message->sender_user_id == deleted_user_id) {
33468         LOG(INFO) << "Remove reply markup in " << dialog_id << ", because bot " << deleted_user_id
33469                   << " isn't a member of the chat";
33470         set_dialog_reply_markup(d, MessageId());
33471       }
33472     }
33473   }
33474 
33475   return result_message;
33476 }
33477 
add_scheduled_message_to_dialog(Dialog * d,unique_ptr<Message> message,bool from_update,bool * need_update,const char * source)33478 MessagesManager::Message *MessagesManager::add_scheduled_message_to_dialog(Dialog *d, unique_ptr<Message> message,
33479                                                                            bool from_update, bool *need_update,
33480                                                                            const char *source) {
33481   CHECK(message != nullptr);
33482   CHECK(d != nullptr);
33483   CHECK(need_update != nullptr);
33484   CHECK(source != nullptr);
33485 
33486   DialogId dialog_id = d->dialog_id;
33487   MessageId message_id = message->message_id;
33488   CHECK(message_id.is_valid_scheduled());
33489   CHECK(!message->notification_id.is_valid());
33490   CHECK(!message->removed_notification_id.is_valid());
33491 
33492   message->top_thread_message_id = MessageId();
33493 
33494   if (d->deleted_message_ids.count(message_id)) {
33495     LOG(INFO) << "Skip adding deleted " << message_id << " to " << dialog_id << " from " << source;
33496     debug_add_message_to_dialog_fail_reason_ = "adding deleted scheduled message";
33497     return nullptr;
33498   }
33499 
33500   if (message_id.is_scheduled_server() &&
33501       d->deleted_scheduled_server_message_ids.count(message_id.get_scheduled_server_message_id())) {
33502     LOG(INFO) << "Skip adding deleted " << message_id << " to " << dialog_id << " from " << source;
33503     debug_add_message_to_dialog_fail_reason_ = "adding deleted scheduled server message";
33504     return nullptr;
33505   }
33506 
33507   if (dialog_id.get_type() == DialogType::SecretChat) {
33508     LOG(ERROR) << "Tried to add " << message_id << " to " << dialog_id << " from " << source;
33509     debug_add_message_to_dialog_fail_reason_ = "skip adding scheduled message to secret chat";
33510     return nullptr;
33511   }
33512   if (message->ttl != 0 || message->ttl_expires_at != 0) {
33513     LOG(ERROR) << "Tried to add " << message_id << " with TTL " << message->ttl << "/" << message->ttl_expires_at
33514                << " to " << dialog_id << " from " << source;
33515     debug_add_message_to_dialog_fail_reason_ = "skip adding secret scheduled message";
33516     return nullptr;
33517   }
33518   if (message->ttl_period != 0) {
33519     LOG(ERROR) << "Tried to add " << message_id << " with TTL period " << message->ttl_period << " to " << dialog_id
33520                << " from " << source;
33521     debug_add_message_to_dialog_fail_reason_ = "skip adding auto-deleting scheduled message";
33522     return nullptr;
33523   }
33524   if (td_->auth_manager_->is_bot()) {
33525     LOG(ERROR) << "Bot tried to add " << message_id << " to " << dialog_id << " from " << source;
33526     debug_add_message_to_dialog_fail_reason_ = "skip adding scheduled message by bot";
33527     return nullptr;
33528   }
33529 
33530   auto message_content_type = message->content->get_type();
33531   if (is_service_message_content(message_content_type) || message_content_type == MessageContentType::LiveLocation ||
33532       message_content_type == MessageContentType::ExpiredPhoto ||
33533       message_content_type == MessageContentType::ExpiredVideo) {
33534     LOG(ERROR) << "Tried to add " << message_id << " of type " << message_content_type << " to " << dialog_id
33535                << " from " << source;
33536     debug_add_message_to_dialog_fail_reason_ = "skip adding message of unexpected type";
33537     return nullptr;
33538   }
33539 
33540   {
33541     Message *m = message->from_database ? get_message(d, message_id)
33542                                         : get_message_force(d, message_id, "add_scheduled_message_to_dialog");
33543     if (m != nullptr) {
33544       auto old_message_id = m->message_id;
33545       LOG(INFO) << "Adding already existing " << old_message_id << " in " << dialog_id << " from " << source;
33546       set_message_id(message, old_message_id);
33547       if (!message->from_database) {
33548         auto old_file_ids = get_message_content_file_ids(m->content.get(), td_);
33549         bool need_update_dialog_pos = false;
33550         update_message(d, m, std::move(message), &need_update_dialog_pos, true);
33551         CHECK(need_update_dialog_pos == false);
33552         change_message_files(dialog_id, m, old_file_ids);
33553       }
33554       if (old_message_id != message_id) {
33555         being_readded_message_id_ = {dialog_id, old_message_id};
33556         message = do_delete_scheduled_message(d, old_message_id, false, "add_scheduled_message_to_dialog");
33557         CHECK(message != nullptr);
33558         send_update_delete_messages(dialog_id, {message->message_id.get()}, false, false);
33559         set_message_id(message, message_id);
33560         message->from_database = false;
33561       } else {
33562         *need_update = false;
33563         return m;
33564       }
33565     }
33566   }
33567 
33568   LOG(INFO) << "Adding not found " << message_id << " to " << dialog_id << " from " << source;
33569 
33570   const Message *m = message.get();
33571   if (m->message_id.is_yet_unsent() && m->reply_to_message_id.is_valid() && !m->reply_to_message_id.is_yet_unsent()) {
33572     replied_by_yet_unsent_messages_[FullMessageId{dialog_id, m->reply_to_message_id}]++;
33573   }
33574 
33575   if (!m->from_database && !m->message_id.is_yet_unsent()) {
33576     add_message_to_database(d, m, "add_scheduled_message_to_dialog");
33577   }
33578 
33579   reget_message_from_server_if_needed(dialog_id, m);
33580 
33581   add_message_file_sources(dialog_id, m);
33582 
33583   register_message_content(td_, m->content.get(), {dialog_id, m->message_id}, "add_scheduled_message_to_dialog");
33584 
33585   // must be called after register_message_content, which loads web page
33586   update_message_max_reply_media_timestamp(d, message.get(), false);
33587   update_message_max_own_media_timestamp(d, message.get());
33588 
33589   register_message_reply(d, m);
33590 
33591   if (from_update) {
33592     update_sent_message_contents(dialog_id, m);
33593     update_used_hashtags(dialog_id, m);
33594     update_has_outgoing_messages(dialog_id, m);
33595   }
33596 
33597   if (m->message_id.is_scheduled_server()) {
33598     int32 &date = d->scheduled_message_date[m->message_id.get_scheduled_server_message_id()];
33599     CHECK(date == 0);
33600     date = m->date;
33601   }
33602 
33603   Message *result_message = treap_insert_message(&d->scheduled_messages, std::move(message));
33604   CHECK(result_message != nullptr);
33605   CHECK(d->scheduled_messages != nullptr);
33606   being_readded_message_id_ = FullMessageId();
33607   return result_message;
33608 }
33609 
register_new_local_message_id(Dialog * d,const Message * m)33610 void MessagesManager::register_new_local_message_id(Dialog *d, const Message *m) {
33611   if (m == nullptr) {
33612     return;
33613   }
33614   if (m->message_id.is_scheduled()) {
33615     return;
33616   }
33617   CHECK(m->message_id.is_local());
33618   if (m->top_thread_message_id.is_valid() && m->top_thread_message_id != m->message_id) {
33619     Message *top_m = get_message_force(d, m->top_thread_message_id, "register_new_local_message_id");
33620     if (top_m != nullptr && top_m->top_thread_message_id == top_m->message_id) {
33621       auto it = std::lower_bound(top_m->local_thread_message_ids.begin(), top_m->local_thread_message_ids.end(),
33622                                  m->message_id);
33623       if (it == top_m->local_thread_message_ids.end() || *it != m->message_id) {
33624         top_m->local_thread_message_ids.insert(it, m->message_id);
33625         if (top_m->local_thread_message_ids.size() >= 1000) {
33626           top_m->local_thread_message_ids.erase(top_m->local_thread_message_ids.begin());
33627         }
33628         on_message_changed(d, top_m, false, "register_new_local_message_id");
33629       }
33630     }
33631   }
33632 }
33633 
on_message_changed(const Dialog * d,const Message * m,bool need_send_update,const char * source)33634 void MessagesManager::on_message_changed(const Dialog *d, const Message *m, bool need_send_update, const char *source) {
33635   CHECK(d != nullptr);
33636   CHECK(m != nullptr);
33637   if (need_send_update && m->message_id == d->last_message_id) {
33638     send_update_chat_last_message_impl(d, source);
33639   }
33640 
33641   if (m->message_id == d->last_database_message_id) {
33642     on_dialog_updated(d->dialog_id, source);
33643   }
33644 
33645   if (!m->message_id.is_yet_unsent()) {
33646     add_message_to_database(d, m, source);
33647   }
33648 }
33649 
add_message_to_database(const Dialog * d,const Message * m,const char * source)33650 void MessagesManager::add_message_to_database(const Dialog *d, const Message *m, const char *source) {
33651   if (!G()->parameters().use_message_db) {
33652     return;
33653   }
33654 
33655   CHECK(d != nullptr);
33656   CHECK(m != nullptr);
33657   MessageId message_id = m->message_id;
33658 
33659   LOG(INFO) << "Add " << FullMessageId(d->dialog_id, message_id) << " to database from " << source;
33660 
33661   if (message_id.is_scheduled()) {
33662     set_dialog_has_scheduled_database_messages(d->dialog_id, true);
33663     G()->td_db()->get_messages_db_async()->add_scheduled_message({d->dialog_id, message_id}, log_event_store(*m),
33664                                                                  Auto());  // TODO Promise
33665     return;
33666   }
33667   LOG_CHECK(message_id.is_server() || message_id.is_local()) << source;
33668 
33669   ServerMessageId unique_message_id;
33670   int64 random_id = 0;
33671   int64 search_id = 0;
33672   string text;
33673   switch (d->dialog_id.get_type()) {
33674     case DialogType::User:
33675     case DialogType::Chat:
33676       if (message_id.is_server()) {
33677         unique_message_id = message_id.get_server_message_id();
33678       }
33679       // FOR DEBUG
33680       // text = get_message_search_text(m);
33681       // if (!text.empty()) {
33682       //   search_id = (static_cast<int64>(m->date) << 32) | static_cast<uint32>(Random::secure_int32());
33683       // }
33684       break;
33685     case DialogType::Channel:
33686       break;
33687     case DialogType::SecretChat:
33688       random_id = m->random_id;
33689       text = get_message_search_text(m);
33690       if (!text.empty()) {
33691         search_id = (static_cast<int64>(m->date) << 32) | static_cast<uint32>(m->random_id);
33692       }
33693       break;
33694     case DialogType::None:
33695     default:
33696       UNREACHABLE();
33697   }
33698 
33699   int32 ttl_expires_at = 0;
33700   if (m->ttl_expires_at != 0) {
33701     ttl_expires_at = static_cast<int32>(m->ttl_expires_at - Time::now() + G()->server_time()) + 1;
33702   }
33703   if (m->ttl_period != 0 && (ttl_expires_at == 0 || m->date + m->ttl_period < ttl_expires_at)) {
33704     ttl_expires_at = m->date + m->ttl_period;
33705   }
33706   G()->td_db()->get_messages_db_async()->add_message({d->dialog_id, message_id}, unique_message_id,
33707                                                      get_message_sender(m), random_id, ttl_expires_at,
33708                                                      get_message_index_mask(d->dialog_id, m), search_id, text,
33709                                                      m->notification_id, m->top_thread_message_id, log_event_store(*m),
33710                                                      Auto());  // TODO Promise
33711 }
33712 
delete_all_dialog_messages_from_database(Dialog * d,MessageId max_message_id,const char * source)33713 void MessagesManager::delete_all_dialog_messages_from_database(Dialog *d, MessageId max_message_id,
33714                                                                const char *source) {
33715   CHECK(d != nullptr);
33716   CHECK(max_message_id.is_valid());
33717   if (d->new_secret_chat_notification_id.is_valid()) {
33718     remove_new_secret_chat_notification(d, true);
33719   }
33720   if (d->pinned_message_notification_message_id.is_valid() &&
33721       d->pinned_message_notification_message_id <= max_message_id) {
33722     remove_dialog_pinned_message_notification(d, source);
33723   }
33724   remove_message_dialog_notifications(d, max_message_id, false, source);
33725   remove_message_dialog_notifications(d, max_message_id, true, source);
33726 
33727   if (!G()->parameters().use_message_db) {
33728     return;
33729   }
33730 
33731   auto dialog_id = d->dialog_id;
33732   LOG(INFO) << "Delete all messages in " << dialog_id << " from database up to " << max_message_id << " from "
33733             << source;
33734   /*
33735   if (dialog_id.get_type() == DialogType::User && max_message_id.is_server()) {
33736     bool need_save = false;
33737     int i = 0;
33738     for (auto &first_message_id : calls_db_state_.first_calls_database_message_id_by_index) {
33739       if (first_message_id <= max_message_id) {
33740         first_message_id = max_message_id.get_next_server_message_id();
33741         calls_db_state_.message_count_by_index[i] = -1;
33742         need_save = true;
33743       }
33744       i++;
33745     }
33746     if (need_save) {
33747       save_calls_db_state();
33748     }
33749   }
33750   */
33751   G()->td_db()->get_messages_db_async()->delete_all_dialog_messages(dialog_id, max_message_id,
33752                                                                     Auto());  // TODO Promise
33753 }
33754 
33755 class MessagesManager::DeleteMessageLogEvent {
33756  public:
33757   LogEvent::Id id_{0};
33758   FullMessageId full_message_id_;
33759   std::vector<FileId> file_ids_;
33760 
33761   template <class StorerT>
store(StorerT & storer) const33762   void store(StorerT &storer) const {
33763     bool has_file_ids = !file_ids_.empty();
33764     BEGIN_STORE_FLAGS();
33765     STORE_FLAG(has_file_ids);
33766     END_STORE_FLAGS();
33767 
33768     td::store(full_message_id_, storer);
33769     if (has_file_ids) {
33770       td::store(file_ids_, storer);
33771     }
33772   }
33773 
33774   template <class ParserT>
parse(ParserT & parser)33775   void parse(ParserT &parser) {
33776     bool has_file_ids;
33777     BEGIN_PARSE_FLAGS();
33778     PARSE_FLAG(has_file_ids);
33779     END_PARSE_FLAGS();
33780 
33781     td::parse(full_message_id_, parser);
33782     if (has_file_ids) {
33783       td::parse(file_ids_, parser);
33784     }
33785   }
33786 };
33787 
delete_message_files(DialogId dialog_id,const Message * m) const33788 void MessagesManager::delete_message_files(DialogId dialog_id, const Message *m) const {
33789   for (auto file_id : get_message_file_ids(m)) {
33790     if (need_delete_file({dialog_id, m->message_id}, file_id)) {
33791       send_closure(G()->file_manager(), &FileManager::delete_file, file_id, Promise<>(), "delete_message_files");
33792     }
33793   }
33794 }
33795 
need_delete_file(FullMessageId full_message_id,FileId file_id) const33796 bool MessagesManager::need_delete_file(FullMessageId full_message_id, FileId file_id) const {
33797   if (being_readded_message_id_ == full_message_id) {
33798     return false;
33799   }
33800 
33801   auto main_file_id = td_->file_manager_->get_file_view(file_id).file_id();
33802   auto full_message_ids = td_->file_reference_manager_->get_some_message_file_sources(main_file_id);
33803   LOG(INFO) << "Receive " << full_message_ids << " as sources for file " << main_file_id << "/" << file_id << " from "
33804             << full_message_id;
33805   for (const auto &other_full_messsage_id : full_message_ids) {
33806     if (other_full_messsage_id != full_message_id) {
33807       return false;
33808     }
33809   }
33810 
33811   return true;
33812 }
33813 
need_delete_message_files(DialogId dialog_id,const Message * m) const33814 bool MessagesManager::need_delete_message_files(DialogId dialog_id, const Message *m) const {
33815   if (m == nullptr) {
33816     return false;
33817   }
33818 
33819   auto dialog_type = dialog_id.get_type();
33820   if (!m->message_id.is_scheduled() && !m->message_id.is_server() && dialog_type != DialogType::SecretChat) {
33821     return false;
33822   }
33823   if (being_readded_message_id_ == FullMessageId{dialog_id, m->message_id}) {
33824     return false;
33825   }
33826 
33827   if (m->forward_info != nullptr && m->forward_info->from_dialog_id.is_valid() &&
33828       m->forward_info->from_message_id.is_valid()) {
33829     // this function must not try to load the message, because it can be called from
33830     // do_delete_message or add_scheduled_message_to_dialog
33831     const Message *old_m = get_message({m->forward_info->from_dialog_id, m->forward_info->from_message_id});
33832     if (old_m != nullptr && get_message_file_ids(old_m) == get_message_file_ids(m)) {
33833       return false;
33834     }
33835   }
33836 
33837   return true;
33838 }
33839 
delete_message_from_database(Dialog * d,MessageId message_id,const Message * m,bool is_permanently_deleted)33840 void MessagesManager::delete_message_from_database(Dialog *d, MessageId message_id, const Message *m,
33841                                                    bool is_permanently_deleted) {
33842   CHECK(d != nullptr);
33843   if (!message_id.is_valid() && !message_id.is_valid_scheduled()) {
33844     return;
33845   }
33846 
33847   if (message_id.is_yet_unsent()) {
33848     return;
33849   }
33850 
33851   if (m != nullptr && !m->message_id.is_scheduled() && m->message_id.is_local() &&
33852       m->top_thread_message_id.is_valid() && m->top_thread_message_id != m->message_id) {
33853     // must not load the message from the database
33854     Message *top_m = get_message(d, m->top_thread_message_id);
33855     if (top_m != nullptr && top_m->top_thread_message_id == top_m->message_id) {
33856       auto it = std::lower_bound(top_m->local_thread_message_ids.begin(), top_m->local_thread_message_ids.end(),
33857                                  m->message_id);
33858       if (it != top_m->local_thread_message_ids.end() && *it == m->message_id) {
33859         top_m->local_thread_message_ids.erase(it);
33860         on_message_changed(d, top_m, false, "delete_message_from_database");
33861       }
33862     }
33863   }
33864 
33865   if (is_permanently_deleted) {
33866     if (message_id.is_scheduled() && message_id.is_scheduled_server()) {
33867       d->deleted_scheduled_server_message_ids.insert(message_id.get_scheduled_server_message_id());
33868     } else {
33869       // don't store failed to send message identifiers for bots to reduce memory usage
33870       if (m == nullptr || !td_->auth_manager_->is_bot() || !m->is_failed_to_send) {
33871         d->deleted_message_ids.insert(message_id);
33872         send_closure_later(actor_id(this),
33873                            &MessagesManager::update_message_max_reply_media_timestamp_in_replied_messages, d->dialog_id,
33874                            message_id);
33875       }
33876     }
33877 
33878     if (message_id.is_any_server()) {
33879       auto old_message_id = find_old_message_id(d->dialog_id, message_id);
33880       if (old_message_id.is_valid()) {
33881         bool have_old_message = get_message(d, old_message_id) != nullptr;
33882         LOG(WARNING) << "Sent " << FullMessageId{d->dialog_id, message_id}
33883                      << " was deleted before it was received. Have old " << old_message_id << " = " << have_old_message;
33884         send_closure_later(actor_id(this), &MessagesManager::delete_messages, d->dialog_id,
33885                            vector<MessageId>{old_message_id}, false, Promise<Unit>());
33886         delete_update_message_id(d->dialog_id, message_id);
33887       }
33888     }
33889   }
33890 
33891   if (m != nullptr && m->notification_id.is_valid()) {
33892     CHECK(!message_id.is_scheduled());
33893     auto from_mentions = is_from_mention_notification_group(d, m);
33894     auto &group_info = from_mentions ? d->mention_notification_group : d->message_notification_group;
33895 
33896     if (group_info.group_id.is_valid()) {
33897       if (group_info.last_notification_id == m->notification_id) {
33898         // last notification is deleted, need to find new last notification
33899         fix_dialog_last_notification_id(d, from_mentions, m->message_id);
33900       }
33901       if (is_message_notification_active(d, m)) {
33902         send_closure_later(G()->notification_manager(), &NotificationManager::remove_notification, group_info.group_id,
33903                            m->notification_id, true, false, Promise<Unit>(), "delete_message_from_database");
33904       }
33905     }
33906   } else if (!message_id.is_scheduled() && message_id > d->last_new_message_id) {
33907     send_closure_later(G()->notification_manager(), &NotificationManager::remove_temporary_notification_by_message_id,
33908                        d->message_notification_group.group_id, message_id, false, "delete_message_from_database");
33909     send_closure_later(G()->notification_manager(), &NotificationManager::remove_temporary_notification_by_message_id,
33910                        d->mention_notification_group.group_id, message_id, false, "delete_message_from_database");
33911   }
33912 
33913   auto need_delete_files = need_delete_message_files(d->dialog_id, m);
33914   if (need_delete_files) {
33915     delete_message_files(d->dialog_id, m);
33916   }
33917 
33918   if (!G()->parameters().use_message_db) {
33919     return;
33920   }
33921 
33922   DeleteMessageLogEvent log_event;
33923 
33924   log_event.full_message_id_ = {d->dialog_id, message_id};
33925 
33926   if (need_delete_files) {
33927     log_event.file_ids_ = get_message_file_ids(m);
33928   }
33929 
33930   do_delete_message_log_event(log_event);
33931 }
33932 
do_delete_message_log_event(const DeleteMessageLogEvent & log_event) const33933 void MessagesManager::do_delete_message_log_event(const DeleteMessageLogEvent &log_event) const {
33934   CHECK(G()->parameters().use_message_db);
33935 
33936   Promise<Unit> db_promise;
33937   if (!log_event.file_ids_.empty()) {
33938     auto log_event_id = log_event.id_;
33939     if (log_event_id == 0) {
33940       log_event_id =
33941           binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::DeleteMessage, get_log_event_storer(log_event));
33942     }
33943 
33944     MultiPromiseActorSafe mpas{"DeleteMessageMultiPromiseActor"};
33945     mpas.add_promise(
33946         PromiseCreator::lambda([log_event_id, context_weak_ptr = get_context_weak_ptr()](Result<Unit> result) {
33947           auto context = context_weak_ptr.lock();
33948           if (result.is_error() || context == nullptr) {
33949             return;
33950           }
33951           CHECK(context->get_id() == Global::ID);
33952           auto global = static_cast<Global *>(context.get());
33953           if (global->close_flag()) {
33954             return;
33955           }
33956 
33957           binlog_erase(global->td_db()->get_binlog(), log_event_id);
33958         }));
33959 
33960     auto lock = mpas.get_promise();
33961     for (auto file_id : log_event.file_ids_) {
33962       if (need_delete_file(log_event.full_message_id_, file_id)) {
33963         send_closure(G()->file_manager(), &FileManager::delete_file, file_id, mpas.get_promise(),
33964                      "do_delete_message_log_event");
33965       }
33966     }
33967     db_promise = mpas.get_promise();
33968     lock.set_value(Unit());
33969   }
33970 
33971   // message may not exist in the dialog
33972   LOG(INFO) << "Delete " << log_event.full_message_id_ << " from database";
33973   G()->td_db()->get_messages_db_async()->delete_message(log_event.full_message_id_, std::move(db_promise));
33974 }
33975 
attach_message_to_previous(Dialog * d,MessageId message_id,const char * source)33976 void MessagesManager::attach_message_to_previous(Dialog *d, MessageId message_id, const char *source) {
33977   CHECK(d != nullptr);
33978   CHECK(message_id.is_valid());
33979   MessagesIterator it(d, message_id);
33980   Message *m = *it;
33981   CHECK(m != nullptr);
33982   CHECK(m->message_id == message_id);
33983   LOG_CHECK(m->have_previous) << d->dialog_id << " " << message_id << " " << source;
33984   --it;
33985   LOG_CHECK(*it != nullptr) << d->dialog_id << " " << message_id << " " << source;
33986   LOG(INFO) << "Attach " << message_id << " to the previous " << (*it)->message_id << " in " << d->dialog_id;
33987   if ((*it)->have_next) {
33988     m->have_next = true;
33989   } else {
33990     (*it)->have_next = true;
33991   }
33992 }
33993 
attach_message_to_next(Dialog * d,MessageId message_id,const char * source)33994 void MessagesManager::attach_message_to_next(Dialog *d, MessageId message_id, const char *source) {
33995   CHECK(d != nullptr);
33996   CHECK(message_id.is_valid());
33997   MessagesIterator it(d, message_id);
33998   Message *m = *it;
33999   CHECK(m != nullptr);
34000   CHECK(m->message_id == message_id);
34001   LOG_CHECK(m->have_next) << d->dialog_id << " " << message_id << " " << source;
34002   ++it;
34003   LOG_CHECK(*it != nullptr) << d->dialog_id << " " << message_id << " " << source;
34004   LOG(INFO) << "Attach " << message_id << " to the next " << (*it)->message_id << " in " << d->dialog_id;
34005   if ((*it)->have_previous) {
34006     m->have_previous = true;
34007   } else {
34008     (*it)->have_previous = true;
34009   }
34010 }
34011 
update_message(Dialog * d,Message * old_message,unique_ptr<Message> new_message,bool * need_update_dialog_pos,bool is_message_in_dialog)34012 bool MessagesManager::update_message(Dialog *d, Message *old_message, unique_ptr<Message> new_message,
34013                                      bool *need_update_dialog_pos, bool is_message_in_dialog) {
34014   CHECK(d != nullptr);
34015   CHECK(old_message != nullptr);
34016   CHECK(new_message != nullptr);
34017   LOG_CHECK(old_message->message_id == new_message->message_id)
34018       << d->dialog_id << ' ' << old_message->message_id << ' ' << new_message->message_id << ' '
34019       << is_message_in_dialog;
34020   CHECK(old_message->random_y == new_message->random_y);
34021   CHECK(need_update_dialog_pos != nullptr);
34022 
34023   DialogId dialog_id = d->dialog_id;
34024   MessageId message_id = old_message->message_id;
34025   auto old_content_type = old_message->content->get_type();
34026   auto new_content_type = new_message->content->get_type();
34027   bool is_scheduled = message_id.is_scheduled();
34028   bool need_send_update = false;
34029   bool is_new_available = new_content_type != MessageContentType::ChatDeleteHistory;
34030   bool replace_legacy = (old_message->legacy_layer != 0 &&
34031                          (new_message->legacy_layer == 0 || old_message->legacy_layer < new_message->legacy_layer)) ||
34032                         old_content_type == MessageContentType::Unsupported;
34033   bool was_visible_message_reply_info = is_visible_message_reply_info(dialog_id, old_message);
34034   if (old_message->date != new_message->date) {
34035     if (new_message->date > 0) {
34036       if (!(is_scheduled || message_id.is_yet_unsent() ||
34037             (message_id.is_server() && message_id.get_server_message_id().get() == 1) ||
34038             old_content_type == MessageContentType::ChannelMigrateFrom ||
34039             old_content_type == MessageContentType::ChannelCreate)) {
34040         LOG(ERROR) << "Date has changed for " << message_id << " in " << dialog_id << " from " << old_message->date
34041                    << " to " << new_message->date << ", message content type is " << old_content_type << '/'
34042                    << new_content_type;
34043       }
34044       CHECK(old_message->date > 0);
34045       LOG(DEBUG) << "Message date has changed from " << old_message->date << " to " << new_message->date;
34046       old_message->date = new_message->date;
34047       if (!is_scheduled && d->last_message_id == message_id) {
34048         *need_update_dialog_pos = true;
34049       }
34050       need_send_update = true;
34051     } else {
34052       LOG(ERROR) << "Receive " << message_id << " in " << dialog_id << " with wrong date " << new_message->date
34053                  << ", message content type is " << old_content_type << '/' << new_content_type;
34054     }
34055   }
34056   if (old_message->date == old_message->edited_schedule_date) {
34057     old_message->edited_schedule_date = 0;
34058   }
34059   bool is_edited = false;
34060   int32 old_shown_edit_date = old_message->hide_edit_date ? 0 : old_message->edit_date;
34061   if (old_message->edit_date != new_message->edit_date) {
34062     if (new_message->edit_date > 0) {
34063       if (new_message->edit_date > old_message->edit_date) {
34064         LOG(DEBUG) << "Message edit date has changed from " << old_message->edit_date << " to "
34065                    << new_message->edit_date;
34066 
34067         old_message->edit_date = new_message->edit_date;
34068         need_send_update = true;
34069       }
34070     } else {
34071       LOG(ERROR) << "Receive " << message_id << " in " << dialog_id << " of type " << old_content_type << "/"
34072                  << new_content_type << " with wrong edit date " << new_message->edit_date
34073                  << ", old edit date = " << old_message->edit_date;
34074     }
34075   }
34076 
34077   if (old_message->author_signature != new_message->author_signature) {
34078     LOG(DEBUG) << "Author signature has changed for " << message_id << " in " << dialog_id << " sent by "
34079                << old_message->sender_user_id << "/" << new_message->sender_user_id << " or "
34080                << old_message->sender_dialog_id << "/" << new_message->sender_dialog_id << " from "
34081                << old_message->author_signature << " to " << new_message->author_signature;
34082     old_message->author_signature = std::move(new_message->author_signature);
34083     need_send_update = true;
34084   }
34085   if (old_message->sender_user_id != new_message->sender_user_id) {
34086     // there can be race for sent signed posts or changed anonymous flag
34087     LOG_IF(ERROR, old_message->sender_user_id != UserId() && new_message->sender_user_id != UserId())
34088         << message_id << " in " << dialog_id << " has changed sender from " << old_message->sender_user_id << " to "
34089         << new_message->sender_user_id << ", message content type is " << old_content_type << '/' << new_content_type;
34090 
34091     LOG_IF(WARNING, (new_message->sender_user_id.is_valid() || old_message->author_signature.empty()) &&
34092                         !old_message->sender_dialog_id.is_valid() && !new_message->sender_dialog_id.is_valid())
34093         << "Update message sender from " << old_message->sender_user_id << " to " << new_message->sender_user_id
34094         << " in " << dialog_id;
34095     LOG(DEBUG) << "Change message sender";
34096     old_message->sender_user_id = new_message->sender_user_id;
34097     need_send_update = true;
34098   }
34099   if (old_message->sender_dialog_id != new_message->sender_dialog_id) {
34100     // there can be race for changed anonymous flag
34101     LOG_IF(ERROR, old_message->sender_dialog_id != DialogId() && new_message->sender_dialog_id != DialogId())
34102         << message_id << " in " << dialog_id << " has changed sender from " << old_message->sender_dialog_id << " to "
34103         << new_message->sender_dialog_id << ", message content type is " << old_content_type << '/' << new_content_type;
34104 
34105     LOG(DEBUG) << "Change message sender";
34106     old_message->sender_dialog_id = new_message->sender_dialog_id;
34107     need_send_update = true;
34108   }
34109   if (old_message->forward_info == nullptr) {
34110     if (new_message->forward_info != nullptr) {
34111       if (!replace_legacy) {
34112         LOG(ERROR) << message_id << " in " << dialog_id << " has received forward info " << *new_message->forward_info
34113                    << ", really forwarded from " << old_message->real_forward_from_message_id << " in "
34114                    << old_message->real_forward_from_dialog_id << ", message content type is " << old_content_type
34115                    << '/' << new_content_type;
34116       }
34117       old_message->forward_info = std::move(new_message->forward_info);
34118       need_send_update = true;
34119     }
34120   } else {
34121     if (new_message->forward_info != nullptr) {
34122       if (old_message->forward_info->author_signature != new_message->forward_info->author_signature) {
34123         old_message->forward_info->author_signature = new_message->forward_info->author_signature;
34124         LOG(DEBUG) << "Change message signature";
34125         need_send_update = true;
34126       }
34127       if (*old_message->forward_info != *new_message->forward_info) {
34128         bool need_warning = [&] {
34129           if (replace_legacy) {
34130             return false;
34131           }
34132           if (!is_scheduled && !message_id.is_yet_unsent()) {
34133             return true;
34134           }
34135           return !is_forward_info_sender_hidden(new_message->forward_info.get()) &&
34136                  !is_forward_info_sender_hidden(old_message->forward_info.get());
34137         }();
34138         if (need_warning) {
34139           LOG(ERROR) << message_id << " in " << dialog_id << " has changed forward info from "
34140                      << *old_message->forward_info << " to " << *new_message->forward_info << ", really forwarded from "
34141                      << old_message->real_forward_from_message_id << " in " << old_message->real_forward_from_dialog_id
34142                      << ", message content type is " << old_content_type << '/' << new_content_type;
34143         }
34144         old_message->forward_info = std::move(new_message->forward_info);
34145         need_send_update = true;
34146       }
34147     } else if (is_new_available) {
34148       LOG(ERROR) << message_id << " in " << dialog_id << " sent by " << old_message->sender_user_id << "/"
34149                  << old_message->sender_dialog_id << " has lost forward info " << *old_message->forward_info
34150                  << ", really forwarded from " << old_message->real_forward_from_message_id << " in "
34151                  << old_message->real_forward_from_dialog_id << ", message content type is " << old_content_type << '/'
34152                  << new_content_type;
34153       old_message->forward_info = nullptr;
34154       need_send_update = true;
34155     }
34156   }
34157   if (old_message->had_forward_info != new_message->had_forward_info) {
34158     old_message->had_forward_info = new_message->had_forward_info;
34159     need_send_update = true;
34160   }
34161   if (old_message->notification_id != new_message->notification_id) {
34162     CHECK(!is_scheduled);
34163     if (old_message->notification_id.is_valid()) {
34164       if (new_message->notification_id.is_valid()) {
34165         LOG(ERROR) << "Notification identifier for " << message_id << " in " << dialog_id
34166                    << " has tried to change from " << old_message->notification_id << " to "
34167                    << new_message->notification_id << ", message content type is " << old_content_type << '/'
34168                    << new_content_type;
34169       }
34170     } else {
34171       CHECK(new_message->notification_id.is_valid());
34172       add_notification_id_to_message_id_correspondence(d, new_message->notification_id, message_id);
34173       old_message->notification_id = new_message->notification_id;
34174     }
34175   }
34176   if (new_message->is_mention_notification_disabled) {
34177     old_message->is_mention_notification_disabled = true;
34178   }
34179   if (!new_message->from_database) {
34180     old_message->from_database = false;
34181   }
34182 
34183   if (old_message->ttl_period != new_message->ttl_period) {
34184     if (old_message->ttl_period != 0 || !message_id.is_yet_unsent()) {
34185       LOG(ERROR) << message_id << " in " << dialog_id << " has changed TTL period from " << old_message->ttl_period
34186                  << " to " << new_message->ttl_period;
34187     } else {
34188       LOG(DEBUG) << "Change message TTL period";
34189       old_message->ttl_period = new_message->ttl_period;
34190       need_send_update = true;
34191     }
34192   }
34193 
34194   if (old_message->reply_to_message_id != new_message->reply_to_message_id) {
34195     // Can't check "&& get_message_force(d, old_message->reply_to_message_id, "update_message") == nullptr", because it
34196     // can change message tree and invalidate reference to old_message
34197     if (new_message->reply_to_message_id == MessageId() || replace_legacy) {
34198       LOG(DEBUG) << "Drop message reply_to_message_id";
34199       unregister_message_reply(d, old_message);
34200       old_message->reply_to_message_id = MessageId();
34201       update_message_max_reply_media_timestamp(d, old_message, true);
34202       need_send_update = true;
34203     } else if (is_new_available) {
34204       LOG(ERROR) << message_id << " in " << dialog_id << " has changed message it is reply to from "
34205                  << old_message->reply_to_message_id << " to " << new_message->reply_to_message_id
34206                  << ", message content type is " << old_content_type << '/' << new_content_type;
34207     }
34208   }
34209   if (old_message->reply_in_dialog_id != new_message->reply_in_dialog_id) {
34210     if (new_message->reply_in_dialog_id == DialogId() || replace_legacy) {
34211       LOG(DEBUG) << "Drop message reply_in_dialog_id";
34212       old_message->reply_in_dialog_id = DialogId();
34213       need_send_update = true;
34214     } else if (is_new_available && old_message->reply_in_dialog_id.is_valid()) {
34215       LOG(ERROR) << message_id << " in " << dialog_id << " has changed dialog it is reply in from "
34216                  << old_message->reply_in_dialog_id << " to " << new_message->reply_in_dialog_id
34217                  << ", message content type is " << old_content_type << '/' << new_content_type;
34218     }
34219   }
34220   if (old_message->top_thread_message_id != new_message->top_thread_message_id) {
34221     if (new_message->top_thread_message_id == MessageId() || old_message->top_thread_message_id == MessageId()) {
34222       LOG(DEBUG) << "Change message thread from " << old_message->top_thread_message_id << " to "
34223                  << new_message->top_thread_message_id;
34224       old_message->top_thread_message_id = new_message->top_thread_message_id;
34225       need_send_update = true;
34226     } else if (is_new_available) {
34227       LOG(ERROR) << message_id << " in " << dialog_id << " has changed message thread from "
34228                  << old_message->top_thread_message_id << " to " << new_message->top_thread_message_id
34229                  << ", message content type is " << old_content_type << '/' << new_content_type;
34230     }
34231   }
34232   if (old_message->via_bot_user_id != new_message->via_bot_user_id) {
34233     if ((!message_id.is_yet_unsent() || old_message->via_bot_user_id.is_valid()) && is_new_available &&
34234         !replace_legacy) {
34235       LOG(ERROR) << message_id << " in " << dialog_id << " has changed bot via it is sent from "
34236                  << old_message->via_bot_user_id << " to " << new_message->via_bot_user_id
34237                  << ", message content type is " << old_content_type << '/' << new_content_type;
34238     }
34239     LOG(DEBUG) << "Change message via_bot from " << old_message->via_bot_user_id << " to "
34240                << new_message->via_bot_user_id;
34241     old_message->via_bot_user_id = new_message->via_bot_user_id;
34242     need_send_update = true;
34243 
34244     if (old_message->hide_via_bot && old_message->via_bot_user_id.is_valid()) {
34245       // wrongly set hide_via_bot
34246       old_message->hide_via_bot = false;
34247     }
34248   }
34249   if (old_message->is_outgoing != new_message->is_outgoing && is_new_available) {
34250     if (!replace_legacy && !(message_id.is_scheduled() && dialog_id == get_my_dialog_id())) {
34251       LOG(ERROR) << message_id << " in " << dialog_id << " has changed is_outgoing from " << old_message->is_outgoing
34252                  << " to " << new_message->is_outgoing << ", message content type is " << old_content_type << '/'
34253                  << new_content_type;
34254     }
34255     old_message->is_outgoing = new_message->is_outgoing;
34256     need_send_update = true;
34257   }
34258   LOG_IF(ERROR, old_message->is_channel_post != new_message->is_channel_post)
34259       << message_id << " in " << dialog_id << " has changed is_channel_post from " << old_message->is_channel_post
34260       << " to " << new_message->is_channel_post << ", message content type is " << old_content_type << '/'
34261       << new_content_type;
34262   if (old_message->contains_mention != new_message->contains_mention) {
34263     if (old_message->edit_date == 0 && is_new_available && old_content_type != MessageContentType::PinMessage &&
34264         old_content_type != MessageContentType::ExpiredPhoto && old_content_type != MessageContentType::ExpiredVideo &&
34265         !replace_legacy) {
34266       LOG(ERROR) << message_id << " in " << dialog_id << " has changed contains_mention from "
34267                  << old_message->contains_mention << " to " << new_message->contains_mention
34268                  << ", is_outgoing = " << old_message->is_outgoing << ", message content type is " << old_content_type
34269                  << '/' << new_content_type;
34270     }
34271     // contains_mention flag shouldn't be changed, because the message will not be added to unread mention list
34272     // and we are unable to show/hide message notification
34273     // old_message->contains_mention = new_message->contains_mention;
34274     // need_send_update = true;
34275   }
34276   if (old_message->disable_notification != new_message->disable_notification) {
34277     LOG_IF(ERROR, old_message->edit_date == 0 && is_new_available && !replace_legacy)
34278         << "Disable_notification has changed from " << old_message->disable_notification << " to "
34279         << new_message->disable_notification
34280         << ". Old message: " << to_string(get_message_object(dialog_id, old_message, "update_message"))
34281         << ". New message: " << to_string(get_message_object(dialog_id, new_message.get(), "update_message"));
34282     // disable_notification flag shouldn't be changed, because we are unable to show/hide message notification
34283     // old_message->disable_notification = new_message->disable_notification;
34284     // need_send_update = true;
34285   }
34286   if (old_message->disable_web_page_preview != new_message->disable_web_page_preview) {
34287     old_message->disable_web_page_preview = new_message->disable_web_page_preview;
34288   }
34289 
34290   if (!is_scheduled &&
34291       update_message_contains_unread_mention(d, old_message, new_message->contains_unread_mention, "update_message")) {
34292     need_send_update = true;
34293   }
34294   if (update_message_interaction_info(dialog_id, old_message, new_message->view_count, new_message->forward_count, true,
34295                                       std::move(new_message->reply_info), "update_message")) {
34296     need_send_update = true;
34297   }
34298   if (old_message->noforwards != new_message->noforwards) {
34299     old_message->noforwards = new_message->noforwards;
34300     need_send_update = true;
34301   }
34302   if (old_message->restriction_reasons != new_message->restriction_reasons) {
34303     old_message->restriction_reasons = std::move(new_message->restriction_reasons);
34304     need_send_update = true;
34305   }
34306   if (old_message->legacy_layer != new_message->legacy_layer) {
34307     old_message->legacy_layer = new_message->legacy_layer;
34308   }
34309   if ((old_message->media_album_id == 0 || td_->auth_manager_->is_bot()) && new_message->media_album_id != 0) {
34310     old_message->media_album_id = new_message->media_album_id;
34311     LOG(DEBUG) << "Update message media_album_id";
34312     need_send_update = true;
34313   }
34314   if (old_message->hide_edit_date != new_message->hide_edit_date) {
34315     old_message->hide_edit_date = new_message->hide_edit_date;
34316     if (old_message->edit_date > 0) {
34317       need_send_update = true;
34318     }
34319   }
34320   int32 new_shown_edit_date = old_message->hide_edit_date ? 0 : old_message->edit_date;
34321   if (new_shown_edit_date != old_shown_edit_date) {
34322     is_edited = true;
34323   }
34324 
34325   if (old_message->is_from_scheduled != new_message->is_from_scheduled) {
34326     // is_from_scheduled flag shouldn't be changed, because we are unable to show/hide message notification
34327     // old_message->is_from_scheduled = new_message->is_from_scheduled;
34328   }
34329 
34330   if (!is_scheduled && update_message_is_pinned(d, old_message, new_message->is_pinned, "update_message")) {
34331     need_send_update = true;
34332   }
34333 
34334   if (old_message->edit_date > 0) {
34335     // inline keyboard can be edited
34336     bool reply_markup_changed =
34337         ((old_message->reply_markup == nullptr) != (new_message->reply_markup == nullptr)) ||
34338         (old_message->reply_markup != nullptr && *old_message->reply_markup != *new_message->reply_markup);
34339     if (reply_markup_changed) {
34340       if (d->reply_markup_message_id == message_id && !td_->auth_manager_->is_bot() &&
34341           new_message->reply_markup == nullptr) {
34342         set_dialog_reply_markup(d, MessageId());
34343       }
34344       LOG(DEBUG) << "Update message reply keyboard";
34345       old_message->reply_markup = std::move(new_message->reply_markup);
34346       is_edited = true;
34347       need_send_update = true;
34348     }
34349     old_message->had_reply_markup = false;
34350   } else {
34351     if (old_message->reply_markup == nullptr) {
34352       if (new_message->reply_markup != nullptr) {
34353         // MessageGame and MessageInvoice reply markup can be generated server side
34354         // some forwards retain their reply markup
34355         if (old_content_type != MessageContentType::Game && old_content_type != MessageContentType::Invoice &&
34356             need_message_changed_warning(old_message) && !replace_legacy) {
34357           LOG(ERROR) << message_id << " in " << dialog_id << " has received reply markup " << *new_message->reply_markup
34358                      << ", message content type is " << old_content_type << '/' << new_content_type;
34359         } else {
34360           LOG(DEBUG) << "Add message reply keyboard";
34361         }
34362 
34363         old_message->had_reply_markup = false;
34364         old_message->reply_markup = std::move(new_message->reply_markup);
34365         need_send_update = true;
34366       }
34367     } else {
34368       if (new_message->reply_markup != nullptr) {
34369         if (replace_legacy ||
34370             (message_id.is_yet_unsent() && old_message->reply_markup->type == ReplyMarkup::Type::InlineKeyboard &&
34371              new_message->reply_markup->type == ReplyMarkup::Type::InlineKeyboard)) {
34372           // allow the server to update inline keyboard for sent messages
34373           // this is needed to get correct button_id for UrlAuth buttons
34374           old_message->had_reply_markup = false;
34375           old_message->reply_markup = std::move(new_message->reply_markup);
34376           need_send_update = true;
34377         } else if (need_message_changed_warning(old_message)) {
34378           LOG_IF(WARNING, *old_message->reply_markup != *new_message->reply_markup)
34379               << message_id << " in " << dialog_id << " has changed reply_markup from " << *old_message->reply_markup
34380               << " to " << *new_message->reply_markup;
34381         }
34382       } else {
34383         // if the message is not accessible anymore, then we don't need a warning
34384         if (need_message_changed_warning(old_message) && is_new_available) {
34385           LOG(ERROR) << message_id << " in " << dialog_id << " sent by " << old_message->sender_user_id << "/"
34386                      << old_message->sender_dialog_id << " has lost reply markup " << *old_message->reply_markup
34387                      << ". Old message: " << to_string(get_message_object(dialog_id, old_message, "update_message"))
34388                      << ". New message: "
34389                      << to_string(get_message_object(dialog_id, new_message.get(), "update_message"));
34390         }
34391       }
34392     }
34393   }
34394 
34395   if (old_message->last_access_date < new_message->last_access_date) {
34396     old_message->last_access_date = new_message->last_access_date;
34397   }
34398   if (new_message->is_update_sent) {
34399     old_message->is_update_sent = true;
34400   }
34401 
34402   if (!is_scheduled) {
34403     CHECK(!new_message->have_previous || !new_message->have_next);
34404     if (new_message->have_previous && !old_message->have_previous) {
34405       old_message->have_previous = true;
34406       attach_message_to_previous(d, message_id, "update_message");
34407     } else if (new_message->have_next && !old_message->have_next) {
34408       old_message->have_next = true;
34409       attach_message_to_next(d, message_id, "update_message");
34410     }
34411   }
34412 
34413   if (update_message_content(dialog_id, old_message, std::move(new_message->content), true,
34414                              message_id.is_yet_unsent() && new_message->edit_date == 0, is_message_in_dialog)) {
34415     need_send_update = true;
34416   }
34417 
34418   if (was_visible_message_reply_info && !is_visible_message_reply_info(dialog_id, old_message)) {
34419     send_update_message_interaction_info(dialog_id, old_message);
34420   }
34421 
34422   if (is_edited && !td_->auth_manager_->is_bot()) {
34423     d->last_edited_message_id = message_id;
34424     send_update_message_edited(dialog_id, old_message);
34425   }
34426 
34427   if (!was_visible_message_reply_info && is_visible_message_reply_info(dialog_id, old_message)) {
34428     send_update_message_interaction_info(dialog_id, old_message);
34429   }
34430 
34431   on_message_changed(d, old_message, need_send_update, "update_message");
34432   return need_send_update;
34433 }
34434 
need_message_changed_warning(const Message * old_message)34435 bool MessagesManager::need_message_changed_warning(const Message *old_message) {
34436   if (old_message->edit_date > 0) {
34437     // message was edited
34438     return false;
34439   }
34440   if (old_message->message_id.is_yet_unsent() &&
34441       (old_message->forward_info != nullptr || old_message->had_forward_info ||
34442        old_message->real_forward_from_dialog_id.is_valid())) {
34443     // original message may be edited
34444     return false;
34445   }
34446   if (old_message->ttl > 0) {
34447     // message can expire
34448     return false;
34449   }
34450   return true;
34451 }
34452 
update_message_content(DialogId dialog_id,Message * old_message,unique_ptr<MessageContent> new_content,bool need_send_update_message_content,bool need_merge_files,bool is_message_in_dialog)34453 bool MessagesManager::update_message_content(DialogId dialog_id, Message *old_message,
34454                                              unique_ptr<MessageContent> new_content,
34455                                              bool need_send_update_message_content, bool need_merge_files,
34456                                              bool is_message_in_dialog) {
34457   bool is_content_changed = false;
34458   bool need_update = false;
34459   unique_ptr<MessageContent> &old_content = old_message->content;
34460   MessageContentType old_content_type = old_content->get_type();
34461   MessageContentType new_content_type = new_content->get_type();
34462 
34463   auto old_file_id = get_message_content_any_file_id(old_content.get());
34464   bool need_finish_upload = old_file_id.is_valid() && need_merge_files;
34465   if (old_content_type != new_content_type) {
34466     if (old_message->ttl > 0 && old_message->ttl_expires_at > 0 &&
34467         ((new_content_type == MessageContentType::ExpiredPhoto && old_content_type == MessageContentType::Photo) ||
34468          (new_content_type == MessageContentType::ExpiredVideo && old_content_type == MessageContentType::Video))) {
34469       LOG(INFO) << "Do not apply expired message content early";
34470     } else {
34471       need_update = true;
34472       LOG(INFO) << "Message content has changed its type from " << old_content_type << " to " << new_content_type;
34473 
34474       old_message->is_content_secret = is_secret_message_content(old_message->ttl, new_content->get_type());
34475     }
34476 
34477     if (need_merge_files && old_file_id.is_valid()) {
34478       auto new_file_id = get_message_content_any_file_id(new_content.get());
34479       if (new_file_id.is_valid()) {
34480         FileView old_file_view = td_->file_manager_->get_file_view(old_file_id);
34481         FileView new_file_view = td_->file_manager_->get_file_view(new_file_id);
34482         // if file type has changed, but file size remains the same, we are trying to update local location of the new
34483         // file with the old local location
34484         if (old_file_view.has_local_location() && !new_file_view.has_local_location() && old_file_view.size() != 0 &&
34485             old_file_view.size() == new_file_view.size()) {
34486           auto old_file_type = old_file_view.get_type();
34487           auto new_file_type = new_file_view.get_type();
34488           auto is_document_file_type = [](FileType file_type) {
34489             switch (file_type) {
34490               case FileType::Animation:
34491               case FileType::Audio:
34492               case FileType::Document:
34493               case FileType::DocumentAsFile:
34494               case FileType::Sticker:
34495               case FileType::Video:
34496               case FileType::VideoNote:
34497               case FileType::VoiceNote:
34498                 return true;
34499               default:
34500                 return false;
34501             }
34502           };
34503 
34504           if (is_document_file_type(old_file_type) && is_document_file_type(new_file_type)) {
34505             auto &old_location = old_file_view.local_location();
34506             auto r_file_id = td_->file_manager_->register_local(
34507                 FullLocalFileLocation(new_file_type, old_location.path_, old_location.mtime_nsec_), dialog_id,
34508                 old_file_view.size());
34509             if (r_file_id.is_ok()) {
34510               LOG_STATUS(td_->file_manager_->merge(new_file_id, r_file_id.ok()));
34511             }
34512           }
34513         }
34514       }
34515     }
34516   } else {
34517     merge_message_contents(td_, old_content.get(), new_content.get(), need_message_changed_warning(old_message),
34518                            dialog_id, need_merge_files, is_content_changed, need_update);
34519   }
34520   if (need_finish_upload) {
34521     // the file is likely to be already merged with a server file, but if not we need to
34522     // cancel file upload of the main file to allow next upload with the same file to succeed
34523     cancel_upload_file(old_file_id);
34524   }
34525 
34526   if (is_content_changed || need_update) {
34527     if (is_message_in_dialog) {
34528       reregister_message_content(td_, old_content.get(), new_content.get(), {dialog_id, old_message->message_id},
34529                                  "update_message_content");
34530     }
34531     old_content = std::move(new_content);
34532     old_message->last_edit_pts = 0;
34533     update_message_content_file_id_remote(old_content.get(), old_file_id);
34534   } else {
34535     update_message_content_file_id_remote(old_content.get(), get_message_content_any_file_id(new_content.get()));
34536   }
34537   if (is_content_changed && !need_update) {
34538     LOG(INFO) << "Content of " << old_message->message_id << " in " << dialog_id << " has changed";
34539   }
34540 
34541   if (need_update && need_send_update_message_content) {
34542     send_update_message_content(dialog_id, old_message, is_message_in_dialog, "update_message_content");
34543   }
34544   return need_update;
34545 }
34546 
get_dialog_by_message_id(MessageId message_id)34547 MessagesManager::Dialog *MessagesManager::get_dialog_by_message_id(MessageId message_id) {
34548   CHECK(message_id.is_valid() && message_id.is_server());
34549   auto it = message_id_to_dialog_id_.find(message_id);
34550   if (it == message_id_to_dialog_id_.end()) {
34551     if (G()->parameters().use_message_db) {
34552       auto r_value =
34553           G()->td_db()->get_messages_db_sync()->get_message_by_unique_message_id(message_id.get_server_message_id());
34554       if (r_value.is_ok()) {
34555         Message *m = on_get_message_from_database(r_value.ok(), false, "get_dialog_by_message_id");
34556         if (m != nullptr) {
34557           auto dialog_id = r_value.ok().dialog_id;
34558           CHECK(m->message_id == message_id);
34559           LOG_CHECK(message_id_to_dialog_id_[message_id] == dialog_id)
34560               << message_id << ' ' << dialog_id << ' ' << message_id_to_dialog_id_[message_id] << ' '
34561               << m->debug_source;
34562           Dialog *d = get_dialog(dialog_id);
34563           CHECK(d != nullptr);
34564           return d;
34565         }
34566       }
34567     }
34568 
34569     LOG(INFO) << "Can't find the chat by " << message_id;
34570     return nullptr;
34571   }
34572 
34573   return get_dialog(it->second);
34574 }
34575 
get_message_id_by_random_id(Dialog * d,int64 random_id,const char * source)34576 MessageId MessagesManager::get_message_id_by_random_id(Dialog *d, int64 random_id, const char *source) {
34577   CHECK(d != nullptr);
34578   CHECK(d->dialog_id.get_type() == DialogType::SecretChat);
34579   if (random_id == 0) {
34580     return MessageId();
34581   }
34582   auto it = d->random_id_to_message_id.find(random_id);
34583   if (it == d->random_id_to_message_id.end()) {
34584     if (G()->parameters().use_message_db) {
34585       auto r_value = G()->td_db()->get_messages_db_sync()->get_message_by_random_id(d->dialog_id, random_id);
34586       if (r_value.is_ok()) {
34587         debug_add_message_to_dialog_fail_reason_ = "not called";
34588         Message *m = on_get_message_from_database(d, r_value.ok(), false, "get_message_id_by_random_id");
34589         if (m != nullptr) {
34590           LOG_CHECK(m->random_id == random_id)
34591               << random_id << " " << m->random_id << " " << d->random_id_to_message_id[random_id] << " "
34592               << d->random_id_to_message_id[m->random_id] << " " << m->message_id << " " << source << " "
34593               << m->from_database << get_message(d, m->message_id) << " " << m << " "
34594               << debug_add_message_to_dialog_fail_reason_;
34595           LOG_CHECK(d->random_id_to_message_id.count(random_id))
34596               << source << " " << random_id << " " << m->message_id << " " << m->is_failed_to_send << " "
34597               << m->is_outgoing << " " << m->from_database << " " << get_message(d, m->message_id) << " " << m << " "
34598               << debug_add_message_to_dialog_fail_reason_;
34599           LOG_CHECK(d->random_id_to_message_id[random_id] == m->message_id)
34600               << source << " " << random_id << " " << d->random_id_to_message_id[random_id] << " " << m->message_id
34601               << " " << m->is_failed_to_send << " " << m->is_outgoing << " " << m->from_database << " "
34602               << get_message(d, m->message_id) << " " << m << " " << debug_add_message_to_dialog_fail_reason_;
34603           return m->message_id;
34604         }
34605       }
34606     }
34607 
34608     return MessageId();
34609   }
34610 
34611   return it->second;
34612 }
34613 
force_create_dialog(DialogId dialog_id,const char * source,bool expect_no_access,bool force_update_dialog_pos)34614 void MessagesManager::force_create_dialog(DialogId dialog_id, const char *source, bool expect_no_access,
34615                                           bool force_update_dialog_pos) {
34616   LOG_CHECK(dialog_id.is_valid()) << source;
34617   LOG_CHECK(is_inited_) << dialog_id << ' ' << source << ' ' << expect_no_access << ' ' << force_update_dialog_pos;
34618   Dialog *d = get_dialog_force(dialog_id, source);
34619   if (d == nullptr) {
34620     LOG(INFO) << "Force create " << dialog_id << " from " << source;
34621     if (loaded_dialogs_.count(dialog_id) > 0) {
34622       LOG(INFO) << "Skip creation of " << dialog_id << ", because it is being loaded now";
34623       return;
34624     }
34625 
34626     d = add_dialog(dialog_id, "force_create_dialog");
34627     update_dialog_pos(d, "force_create_dialog");
34628 
34629     if (dialog_id.get_type() == DialogType::SecretChat && !d->notification_settings.is_synchronized &&
34630         td_->contacts_manager_->get_secret_chat_state(dialog_id.get_secret_chat_id()) != SecretChatState::Closed) {
34631       // secret chat is being created
34632       // let's copy notification settings from main chat if available
34633       VLOG(notifications) << "Create new secret " << dialog_id << " from " << source;
34634       auto secret_chat_id = dialog_id.get_secret_chat_id();
34635       {
34636         auto user_id = td_->contacts_manager_->get_secret_chat_user_id(secret_chat_id);
34637         Dialog *user_d = get_dialog_force(DialogId(user_id), source);
34638         if (user_d != nullptr && user_d->notification_settings.is_synchronized) {
34639           VLOG(notifications) << "Copy notification settings from " << user_d->dialog_id << " to " << dialog_id;
34640           auto new_notification_settings = user_d->notification_settings;
34641           new_notification_settings.use_default_show_preview = true;
34642           new_notification_settings.show_preview = false;
34643           new_notification_settings.is_secret_chat_show_preview_fixed = true;
34644           update_dialog_notification_settings(dialog_id, &d->notification_settings, new_notification_settings);
34645         } else {
34646           d->notification_settings.is_synchronized = true;
34647         }
34648       }
34649 
34650       if (G()->parameters().use_message_db && !td_->auth_manager_->is_bot() &&
34651           !td_->contacts_manager_->get_secret_chat_is_outbound(secret_chat_id)) {
34652         auto notification_group_id = get_dialog_notification_group_id(dialog_id, d->message_notification_group);
34653         if (notification_group_id.is_valid()) {
34654           if (d->new_secret_chat_notification_id.is_valid()) {
34655             LOG(ERROR) << "Found previously created " << d->new_secret_chat_notification_id << " in " << d->dialog_id
34656                        << ", when creating it from " << source;
34657           } else {
34658             d->new_secret_chat_notification_id = get_next_notification_id(d, notification_group_id, MessageId());
34659             if (d->new_secret_chat_notification_id.is_valid()) {
34660               auto date = td_->contacts_manager_->get_secret_chat_date(secret_chat_id);
34661               bool is_changed = set_dialog_last_notification(dialog_id, d->message_notification_group, date,
34662                                                              d->new_secret_chat_notification_id, "add_new_secret_chat");
34663               CHECK(is_changed);
34664               VLOG(notifications) << "Create " << d->new_secret_chat_notification_id << " with " << secret_chat_id;
34665               send_closure_later(G()->notification_manager(), &NotificationManager::add_notification,
34666                                  notification_group_id, NotificationGroupType::SecretChat, dialog_id, date, dialog_id,
34667                                  false, false, 0, d->new_secret_chat_notification_id,
34668                                  create_new_secret_chat_notification(), "add_new_secret_chat_notification");
34669             }
34670           }
34671         }
34672       }
34673     }
34674     if (!have_input_peer(dialog_id, AccessRights::Read)) {
34675       if (!have_dialog_info(dialog_id)) {
34676         LOG(ERROR) << "Have no info about " << dialog_id << " received from " << source << ", but forced to create it";
34677       } else if (!expect_no_access) {
34678         LOG(ERROR) << "Have no access to " << dialog_id << " received from " << source << ", but forced to create it";
34679       }
34680     }
34681   } else if (force_update_dialog_pos) {
34682     update_dialog_pos(d, "force update dialog pos");
34683   }
34684 }
34685 
add_dialog(DialogId dialog_id,const char * source)34686 MessagesManager::Dialog *MessagesManager::add_dialog(DialogId dialog_id, const char *source) {
34687   LOG(DEBUG) << "Creating " << dialog_id << " from " << source;
34688   CHECK(!have_dialog(dialog_id));
34689   LOG_CHECK(dialog_id.is_valid()) << source;
34690 
34691   if (G()->parameters().use_message_db) {
34692     // TODO preload dialog asynchronously, remove loading from this function
34693     auto r_value = G()->td_db()->get_dialog_db_sync()->get_dialog(dialog_id);
34694     if (r_value.is_ok()) {
34695       LOG(INFO) << "Synchronously loaded " << dialog_id << " from database from " << source;
34696       return add_new_dialog(parse_dialog(dialog_id, r_value.ok(), source), true, source);
34697     }
34698   }
34699 
34700   auto d = make_unique<Dialog>();
34701   d->dialog_id = dialog_id;
34702   invalidate_message_indexes(d.get());
34703 
34704   return add_new_dialog(std::move(d), false, source);
34705 }
34706 
add_new_dialog(unique_ptr<Dialog> && d,bool is_loaded_from_database,const char * source)34707 MessagesManager::Dialog *MessagesManager::add_new_dialog(unique_ptr<Dialog> &&d, bool is_loaded_from_database,
34708                                                          const char *source) {
34709   auto dialog_id = d->dialog_id;
34710   LOG_CHECK(is_inited_) << dialog_id << ' ' << is_loaded_from_database << ' ' << source;
34711   switch (dialog_id.get_type()) {
34712     case DialogType::User:
34713       if (dialog_id == get_my_dialog_id() && d->last_read_inbox_message_id == MessageId::max() &&
34714           d->last_read_outbox_message_id == MessageId::max()) {
34715         d->last_read_inbox_message_id = d->last_new_message_id;
34716         d->last_read_outbox_message_id = d->last_new_message_id;
34717       }
34718       d->has_bots = dialog_id.get_user_id() != ContactsManager::get_replies_bot_user_id() &&
34719                     td_->contacts_manager_->is_user_bot(dialog_id.get_user_id());
34720       d->is_has_bots_inited = true;
34721       break;
34722     case DialogType::Chat:
34723       d->is_is_blocked_inited = true;
34724       break;
34725     case DialogType::Channel: {
34726       auto channel_type = td_->contacts_manager_->get_channel_type(dialog_id.get_channel_id());
34727       if (channel_type == ContactsManager::ChannelType::Broadcast) {
34728         d->last_read_outbox_message_id = MessageId::max();
34729         d->is_last_read_outbox_message_id_inited = true;
34730       }
34731 
34732       auto pts = load_channel_pts(dialog_id);
34733       if (pts > 0) {
34734         d->pts = pts;
34735         if (is_debug_message_op_enabled()) {
34736           d->debug_message_op.emplace_back(Dialog::MessageOp::SetPts, pts, "add_new_dialog");
34737         }
34738       }
34739       break;
34740     }
34741     case DialogType::SecretChat:
34742       if (d->last_new_message_id.get() <= MessageId::min().get()) {
34743         LOG(INFO) << "Set " << dialog_id << " last new message in add_new_dialog from " << source;
34744         d->last_new_message_id = MessageId::min().get_next_message_id(MessageType::Local);
34745       }
34746 
34747       if (!d->notification_settings.is_secret_chat_show_preview_fixed) {
34748         d->notification_settings.use_default_show_preview = true;
34749         d->notification_settings.show_preview = false;
34750         d->notification_settings.is_secret_chat_show_preview_fixed = true;
34751         on_dialog_updated(dialog_id, "fix secret chat show preview");
34752       }
34753 
34754       d->have_full_history = true;
34755       d->need_restore_reply_markup = false;
34756       d->is_last_read_inbox_message_id_inited = true;
34757       d->is_last_read_outbox_message_id_inited = true;
34758       d->is_last_pinned_message_id_inited = true;
34759       d->is_theme_name_inited = true;
34760       d->is_is_blocked_inited = true;
34761       if (!d->is_folder_id_inited && !td_->auth_manager_->is_bot()) {
34762         do_set_dialog_folder_id(
34763             d.get(), td_->contacts_manager_->get_secret_chat_initial_folder_id(dialog_id.get_secret_chat_id()));
34764       }
34765       d->message_ttl_setting =
34766           MessageTtlSetting(td_->contacts_manager_->get_secret_chat_ttl(dialog_id.get_secret_chat_id()));
34767       d->is_message_ttl_setting_inited = true;
34768       d->has_bots = td_->contacts_manager_->is_user_bot(
34769           td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()));
34770       d->is_has_bots_inited = true;
34771 
34772       break;
34773     case DialogType::None:
34774     default:
34775       UNREACHABLE();
34776   }
34777   if (!is_loaded_from_database) {
34778     on_dialog_updated(dialog_id, "add_new_dialog");
34779   }
34780   if (td_->auth_manager_->is_bot()) {
34781     d->notification_settings.is_synchronized = true;
34782   }
34783   if (is_channel_difference_finished_.erase(dialog_id)) {
34784     d->is_channel_difference_finished = true;
34785   }
34786 
34787   unique_ptr<Message> last_database_message = std::move(d->messages);
34788   MessageId last_database_message_id = d->last_database_message_id;
34789   d->last_database_message_id = MessageId();
34790   int64 order = d->order;
34791   d->order = DEFAULT_ORDER;
34792   int32 last_clear_history_date = d->last_clear_history_date;
34793   MessageId last_clear_history_message_id = d->last_clear_history_message_id;
34794   d->last_clear_history_date = 0;
34795   d->last_clear_history_message_id = MessageId();
34796   DialogId default_join_group_call_as_dialog_id = d->default_join_group_call_as_dialog_id;
34797   if (default_join_group_call_as_dialog_id != dialog_id &&
34798       default_join_group_call_as_dialog_id.get_type() != DialogType::User &&
34799       !have_dialog(default_join_group_call_as_dialog_id)) {
34800     d->default_join_group_call_as_dialog_id = DialogId();
34801   }
34802   DialogId default_send_message_as_dialog_id = d->default_send_message_as_dialog_id;
34803   if (default_send_message_as_dialog_id != dialog_id &&
34804       default_send_message_as_dialog_id.get_type() != DialogType::User &&
34805       !have_dialog(default_send_message_as_dialog_id)) {
34806     d->default_send_message_as_dialog_id = DialogId();
34807   }
34808 
34809   if (d->message_notification_group.group_id.is_valid()) {
34810     notification_group_id_to_dialog_id_.emplace(d->message_notification_group.group_id, dialog_id);
34811   }
34812   if (d->mention_notification_group.group_id.is_valid()) {
34813     notification_group_id_to_dialog_id_.emplace(d->mention_notification_group.group_id, dialog_id);
34814   }
34815   if (pending_dialog_group_call_updates_.count(dialog_id) > 0) {
34816     auto it = pending_dialog_group_call_updates_.find(dialog_id);
34817     bool has_active_group_call = it->second.first;
34818     bool is_group_call_empty = it->second.second;
34819     pending_dialog_group_call_updates_.erase(it);
34820     if (d->has_active_group_call != has_active_group_call || d->is_group_call_empty != is_group_call_empty) {
34821       if (!has_active_group_call) {
34822         d->active_group_call_id = InputGroupCallId();
34823       }
34824       d->has_active_group_call = has_active_group_call;
34825       d->is_group_call_empty = is_group_call_empty;
34826       on_dialog_updated(dialog_id, "pending update_dialog_group_call");
34827     }
34828   }
34829   fix_pending_join_requests(dialog_id, d->pending_join_request_count, d->pending_join_request_user_ids);
34830 
34831   if (!is_loaded_from_database) {
34832     CHECK(order == DEFAULT_ORDER);
34833     CHECK(last_database_message == nullptr);
34834   }
34835 
34836   auto dialog_it = dialogs_.emplace(dialog_id, std::move(d)).first;
34837 
34838   loaded_dialogs_.erase(dialog_id);
34839 
34840   Dialog *dialog = dialog_it->second.get();
34841 
34842   fix_dialog_action_bar(dialog, dialog->action_bar.get());
34843 
34844   send_update_new_chat(dialog);
34845 
34846   fix_new_dialog(dialog, std::move(last_database_message), last_database_message_id, order, last_clear_history_date,
34847                  last_clear_history_message_id, default_join_group_call_as_dialog_id, default_send_message_as_dialog_id,
34848                  is_loaded_from_database);
34849 
34850   return dialog;
34851 }
34852 
fix_new_dialog(Dialog * d,unique_ptr<Message> && last_database_message,MessageId last_database_message_id,int64 order,int32 last_clear_history_date,MessageId last_clear_history_message_id,DialogId default_join_group_call_as_dialog_id,DialogId default_send_message_as_dialog_id,bool is_loaded_from_database)34853 void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr<Message> &&last_database_message,
34854                                      MessageId last_database_message_id, int64 order, int32 last_clear_history_date,
34855                                      MessageId last_clear_history_message_id,
34856                                      DialogId default_join_group_call_as_dialog_id,
34857                                      DialogId default_send_message_as_dialog_id, bool is_loaded_from_database) {
34858   CHECK(d != nullptr);
34859   auto dialog_id = d->dialog_id;
34860   auto dialog_type = dialog_id.get_type();
34861 
34862   if (!td_->auth_manager_->is_bot() && dialog_type == DialogType::SecretChat) {
34863     auto user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id());
34864     if (user_id.is_valid()) {
34865       force_create_dialog(DialogId(user_id), "add chat with user to load/store action_bar and is_blocked");
34866 
34867       Dialog *user_d = get_dialog_force(DialogId(user_id), "fix_new_dialog");
34868       if (user_d != nullptr && d->is_blocked != user_d->is_blocked) {
34869         set_dialog_is_blocked(d, user_d->is_blocked);
34870       }
34871     }
34872   }
34873 
34874   if (d->is_empty && !d->have_full_history) {
34875     LOG(ERROR) << "Drop invalid flag is_empty";
34876     d->is_empty = false;
34877   }
34878 
34879   if (being_added_dialog_id_ != dialog_id && !td_->auth_manager_->is_bot() && !is_dialog_inited(d) &&
34880       dialog_type != DialogType::SecretChat && have_input_peer(dialog_id, AccessRights::Read)) {
34881     // asynchronously get dialog from the server
34882     send_get_dialog_query(dialog_id, Auto(), 0, "fix_new_dialog 20");
34883   }
34884 
34885   if (being_added_dialog_id_ != dialog_id && !d->is_is_blocked_inited && !td_->auth_manager_->is_bot()) {
34886     // asynchronously get is_blocked from the server
34887     get_dialog_info_full(dialog_id, Auto(), "fix_new_dialog init is_blocked");
34888   } else if (being_added_dialog_id_ != dialog_id && !d->is_has_bots_inited && !td_->auth_manager_->is_bot()) {
34889     // asynchronously get has_bots from the server
34890     get_dialog_info_full(dialog_id, Auto(), "fix_new_dialog init has_bots");
34891   } else if (being_added_dialog_id_ != dialog_id && !d->is_theme_name_inited && !td_->auth_manager_->is_bot()) {
34892     // asynchronously get dialog theme identifier from the server
34893     get_dialog_info_full(dialog_id, Auto(), "fix_new_dialog init theme_name");
34894   } else if (being_added_dialog_id_ != dialog_id && !d->is_last_pinned_message_id_inited &&
34895              !td_->auth_manager_->is_bot()) {
34896     // asynchronously get dialog pinned message from the server
34897     get_dialog_pinned_message(dialog_id, Auto());
34898   } else if (being_added_dialog_id_ != dialog_id && !d->is_folder_id_inited && !td_->auth_manager_->is_bot() &&
34899              order != DEFAULT_ORDER) {
34900     // asynchronously get dialog folder identifier from the server
34901     get_dialog_info_full(dialog_id, Auto(), "fix_new_dialog init folder_id");
34902   } else if (!d->is_message_ttl_setting_inited && !td_->auth_manager_->is_bot() &&
34903              have_input_peer(dialog_id, AccessRights::Write)) {
34904     // asynchronously get dialog message TTL setting from the server
34905     get_dialog_info_full(dialog_id, Auto(), "fix_new_dialog init message_ttl_setting");
34906   }
34907   if ((!d->know_action_bar || d->need_repair_action_bar) && !td_->auth_manager_->is_bot() &&
34908       dialog_type != DialogType::SecretChat && dialog_id != get_my_dialog_id() &&
34909       have_input_peer(dialog_id, AccessRights::Read)) {
34910     // asynchronously get action bar from the server
34911     reget_dialog_action_bar(dialog_id, "fix_new_dialog", false);
34912   }
34913   if (d->has_active_group_call && !d->active_group_call_id.is_valid() && !td_->auth_manager_->is_bot()) {
34914     repair_dialog_active_group_call_id(dialog_id);
34915   }
34916 
34917   if (d->notification_settings.is_synchronized && !d->notification_settings.is_use_default_fixed &&
34918       have_input_peer(dialog_id, AccessRights::Read) && !td_->auth_manager_->is_bot()) {
34919     LOG(INFO) << "Reget notification settings of " << dialog_id;
34920     if (dialog_type == DialogType::SecretChat) {
34921       if (d->notification_settings.mute_until == 0 && users_notification_settings_.mute_until == 0) {
34922         d->notification_settings.use_default_mute_until = true;
34923       }
34924       if (d->notification_settings.sound == "default" && users_notification_settings_.sound == "default") {
34925         d->notification_settings.use_default_sound = true;
34926       }
34927       if (d->notification_settings.show_preview && users_notification_settings_.show_preview) {
34928         d->notification_settings.use_default_show_preview = true;
34929       }
34930       d->notification_settings.is_use_default_fixed = true;
34931       on_dialog_updated(dialog_id, "reget notification settings");
34932     } else {
34933       send_get_dialog_notification_settings_query(dialog_id, Promise<>());
34934     }
34935   }
34936   if (td_->auth_manager_->is_bot() || d->notification_settings.use_default_mute_until ||
34937       d->notification_settings.mute_until <= G()->unix_time()) {
34938     d->notification_settings.mute_until = 0;
34939   } else {
34940     schedule_dialog_unmute(dialog_id, false, d->notification_settings.mute_until);
34941   }
34942   if (d->pinned_message_notification_message_id.is_valid()) {
34943     auto pinned_message_id = d->pinned_message_notification_message_id;
34944     if (!d->mention_notification_group.group_id.is_valid()) {
34945       LOG(ERROR) << "Have pinned message notification in " << pinned_message_id << " in " << dialog_id
34946                  << ", but there is no mention notification group";
34947       d->pinned_message_notification_message_id = MessageId();
34948       on_dialog_updated(dialog_id, "fix pinned message notification");
34949     } else if (is_dialog_pinned_message_notifications_disabled(d) ||
34950                pinned_message_id <= d->last_read_inbox_message_id ||
34951                pinned_message_id <= d->mention_notification_group.max_removed_message_id) {
34952       VLOG(notifications) << "Remove disabled pinned message notification in " << pinned_message_id << " in "
34953                           << dialog_id;
34954       send_closure_later(G()->notification_manager(), &NotificationManager::remove_temporary_notification_by_message_id,
34955                          d->mention_notification_group.group_id, pinned_message_id, true,
34956                          "fix pinned message notification");
34957       d->pinned_message_notification_message_id = MessageId();
34958       on_dialog_updated(dialog_id, "fix pinned message notification 2");
34959     }
34960   }
34961   if (d->new_secret_chat_notification_id.is_valid()) {
34962     auto &group_info = d->message_notification_group;
34963     if (d->new_secret_chat_notification_id.get() <= group_info.max_removed_notification_id.get() ||
34964         (group_info.last_notification_date == 0 && group_info.max_removed_notification_id.get() == 0)) {
34965       VLOG(notifications) << "Fix removing new secret chat " << d->new_secret_chat_notification_id << " in "
34966                           << dialog_id;
34967       d->new_secret_chat_notification_id = NotificationId();
34968       on_dialog_updated(dialog_id, "fix new secret chat notification identifier");
34969     }
34970   }
34971 
34972   {
34973     auto it = pending_add_dialog_last_database_message_dependent_dialogs_.find(dialog_id);
34974     if (it != pending_add_dialog_last_database_message_dependent_dialogs_.end()) {
34975       auto pending_dialog_ids = std::move(it->second);
34976       pending_add_dialog_last_database_message_dependent_dialogs_.erase(it);
34977 
34978       for (auto &pending_dialog_id : pending_dialog_ids) {
34979         auto &counter_message = pending_add_dialog_last_database_message_[pending_dialog_id];
34980         CHECK(counter_message.first > 0);
34981         counter_message.first--;
34982         if (counter_message.first == 0) {
34983           add_dialog_last_database_message(get_dialog(pending_dialog_id), std::move(counter_message.second));
34984           pending_add_dialog_last_database_message_.erase(pending_dialog_id);
34985         }
34986       }
34987     }
34988   }
34989 
34990   {
34991     auto it = pending_add_default_join_group_call_as_dialog_id_.find(dialog_id);
34992     if (it != pending_add_default_join_group_call_as_dialog_id_.end()) {
34993       auto pending_dialog_ids = std::move(it->second);
34994       pending_add_default_join_group_call_as_dialog_id_.erase(it);
34995 
34996       for (auto &pending_dialog_id : pending_dialog_ids) {
34997         on_update_dialog_default_join_group_call_as_dialog_id(pending_dialog_id, dialog_id, false);
34998       }
34999     }
35000   }
35001 
35002   {
35003     auto it = pending_add_default_send_message_as_dialog_id_.find(dialog_id);
35004     if (it != pending_add_default_send_message_as_dialog_id_.end()) {
35005       auto pending_dialog_ids = std::move(it->second);
35006       pending_add_default_send_message_as_dialog_id_.erase(it);
35007 
35008       for (auto &pending_dialog_id : pending_dialog_ids) {
35009         on_update_dialog_default_send_message_as_dialog_id(pending_dialog_id, dialog_id, false);
35010       }
35011     }
35012   }
35013 
35014   if (dialog_id != being_added_dialog_id_) {
35015     set_dialog_last_clear_history_date(d, last_clear_history_date, last_clear_history_message_id, "fix_new_dialog 8",
35016                                        is_loaded_from_database);
35017 
35018     set_dialog_order(d, order, false, is_loaded_from_database, "fix_new_dialog 9");
35019   }
35020 
35021   if (dialog_type != DialogType::SecretChat && d->last_new_message_id.is_valid() &&
35022       !d->last_new_message_id.is_server()) {
35023     // fix wrong last_new_message_id
35024     d->last_new_message_id = d->last_new_message_id.get_prev_server_message_id();
35025     on_dialog_updated(dialog_id, "fix_new_dialog 10");
35026   }
35027 
35028   bool need_get_history = true;
35029 
35030   // add last database message to dialog
35031   MessageId last_message_id;
35032   if (last_database_message != nullptr) {
35033     need_get_history = false;
35034     last_message_id = last_database_message->message_id;
35035   } else if (last_database_message_id.is_valid()) {
35036     last_message_id = last_database_message_id;
35037   }
35038 
35039   if (!d->last_new_message_id.is_valid() && d->last_new_message_id != MessageId()) {
35040     LOG(ERROR) << "Drop invalid last_new_message_id " << d->last_new_message_id << " in " << dialog_id;
35041     d->last_new_message_id = MessageId();
35042   }
35043   if (last_message_id.is_valid()) {
35044     if ((last_message_id.is_server() || dialog_type == DialogType::SecretChat) && !d->last_new_message_id.is_valid()) {
35045       LOG(ERROR) << "Bugfixing wrong last_new_message_id to " << last_message_id << " in " << dialog_id;
35046       // must be called before set_dialog_first_database_message_id and set_dialog_last_database_message_id
35047       set_dialog_last_new_message_id(d, last_message_id, "fix_new_dialog 1");
35048     }
35049     if (!d->first_database_message_id.is_valid() || d->first_database_message_id > last_message_id) {
35050       LOG(ERROR) << "Bugfixing wrong first_database_message_id from " << d->first_database_message_id << " to "
35051                  << last_message_id << " in " << dialog_id;
35052       set_dialog_first_database_message_id(d, last_message_id, "fix_new_dialog 2");
35053     }
35054     set_dialog_last_database_message_id(d, last_message_id, "fix_new_dialog 3", is_loaded_from_database);
35055   } else if (d->first_database_message_id.is_valid()) {
35056     // ensure that first_database_message_id <= last_database_message_id
35057     if (d->first_database_message_id <= d->last_new_message_id) {
35058       set_dialog_last_database_message_id(d, d->last_new_message_id, "fix_new_dialog 4");
35059     } else {
35060       // can't fix last_database_message_id, drop first_database_message_id; it shouldn't happen anyway
35061       set_dialog_first_database_message_id(d, MessageId(), "fix_new_dialog 5");
35062     }
35063   }
35064   d->debug_first_database_message_id = d->first_database_message_id;
35065   d->debug_last_database_message_id = d->last_database_message_id;
35066   d->debug_last_new_message_id = d->last_new_message_id;
35067 
35068   if (last_database_message != nullptr) {
35069     Dependencies dependencies;
35070     add_message_dependencies(dependencies, last_database_message.get());
35071 
35072     int32 dependent_dialog_count = 0;
35073     for (auto &other_dialog_id : dependencies.dialog_ids) {
35074       if (other_dialog_id.is_valid() && !have_dialog(other_dialog_id)) {
35075         LOG(INFO) << "Postpone adding of last message in " << dialog_id << " because of cyclic dependency with "
35076                   << other_dialog_id;
35077         pending_add_dialog_last_database_message_dependent_dialogs_[other_dialog_id].push_back(dialog_id);
35078         dependent_dialog_count++;
35079       }
35080     };
35081 
35082     if (dependent_dialog_count == 0) {
35083       add_dialog_last_database_message(d, std::move(last_database_message));
35084     } else {
35085       // can't add message immediately, because need to notify first about adding of dependent dialogs
35086       d->pending_last_message_date = last_database_message->date;
35087       d->pending_last_message_id = last_database_message->message_id;
35088       pending_add_dialog_last_database_message_[dialog_id] = {dependent_dialog_count, std::move(last_database_message)};
35089     }
35090   } else if (last_database_message_id.is_valid()) {
35091     auto date = DialogDate(order, dialog_id).get_date();
35092     if (date < MIN_PINNED_DIALOG_DATE) {
35093       d->pending_last_message_date = date;
35094       d->pending_last_message_id = last_database_message_id;
35095     }
35096   }
35097 
35098   if (default_join_group_call_as_dialog_id != d->default_join_group_call_as_dialog_id) {
35099     CHECK(default_join_group_call_as_dialog_id.is_valid());
35100     CHECK(!d->default_join_group_call_as_dialog_id.is_valid());
35101     if (!have_dialog(default_join_group_call_as_dialog_id)) {
35102       LOG(INFO) << "Postpone adding of default join voice chat as " << default_join_group_call_as_dialog_id << " in "
35103                 << dialog_id;
35104       pending_add_default_join_group_call_as_dialog_id_[default_join_group_call_as_dialog_id].push_back(dialog_id);
35105     } else {
35106       on_update_dialog_default_join_group_call_as_dialog_id(dialog_id, default_join_group_call_as_dialog_id, false);
35107     }
35108   }
35109 
35110   if (default_send_message_as_dialog_id != d->default_send_message_as_dialog_id) {
35111     CHECK(default_send_message_as_dialog_id.is_valid());
35112     CHECK(!d->default_send_message_as_dialog_id.is_valid());
35113     if (!have_dialog(default_send_message_as_dialog_id)) {
35114       LOG(INFO) << "Postpone adding of default join voice chat as " << default_send_message_as_dialog_id << " in "
35115                 << dialog_id;
35116       pending_add_default_send_message_as_dialog_id_[default_send_message_as_dialog_id].push_back(dialog_id);
35117     } else {
35118       on_update_dialog_default_send_message_as_dialog_id(dialog_id, default_send_message_as_dialog_id, false);
35119     }
35120   }
35121 
35122   switch (dialog_type) {
35123     case DialogType::User:
35124       break;
35125     case DialogType::Chat:
35126       if (d->last_read_inbox_message_id < d->last_read_outbox_message_id) {
35127         LOG(INFO) << "Last read outbox message is " << d->last_read_outbox_message_id << " in " << dialog_id
35128                   << ", but last read inbox message is " << d->last_read_inbox_message_id;
35129         // can't fix last_read_inbox_message_id by last_read_outbox_message_id because last_read_outbox_message_id is
35130         // just a message identifier not less than an identifier of last read outgoing message and less than
35131         // an identifier of first unread outgoing message, so it may not point to the outgoing message
35132         // read_history_inbox(dialog_id, d->last_read_outbox_message_id, d->server_unread_count, "fix_new_dialog 6");
35133       }
35134       break;
35135     case DialogType::Channel:
35136       break;
35137     case DialogType::SecretChat:
35138       break;
35139     case DialogType::None:
35140     default:
35141       UNREACHABLE();
35142   }
35143 
35144   if (d->delete_last_message_date != 0) {
35145     if (d->last_message_id.is_valid()) {
35146       LOG(ERROR) << "Last " << d->deleted_last_message_id << " in " << dialog_id << " was deleted at "
35147                  << d->delete_last_message_date << ", but have last " << d->last_message_id;
35148       d->delete_last_message_date = 0;
35149       d->deleted_last_message_id = MessageId();
35150       d->is_last_message_deleted_locally = false;
35151       on_dialog_updated(dialog_id, "update_delete_last_message_date");
35152     } else {
35153       need_get_history = true;
35154     }
35155   }
35156 
35157   if (!G()->parameters().use_message_db) {
35158     d->has_loaded_scheduled_messages_from_database = true;
35159   }
35160 
35161   if (dialog_id != being_added_dialog_id_) {
35162     update_dialog_pos(d, "fix_new_dialog 7", true, is_loaded_from_database);
35163   }
35164   if (is_loaded_from_database && d->order != order && order < MAX_ORDINARY_DIALOG_ORDER &&
35165       !td_->contacts_manager_->is_dialog_info_received_from_server(dialog_id) && !d->had_last_yet_unsent_message) {
35166     LOG(ERROR) << dialog_id << " has order " << d->order << " instead of saved to database order " << order;
35167   }
35168 
35169   LOG(INFO) << "Loaded " << dialog_id << " with last new " << d->last_new_message_id << ", first database "
35170             << d->first_database_message_id << ", last database " << d->last_database_message_id << ", last "
35171             << d->last_message_id << " with order " << d->order;
35172   VLOG(notifications) << "Have " << dialog_id << " with message " << d->message_notification_group.group_id
35173                       << " with last " << d->message_notification_group.last_notification_id << " sent at "
35174                       << d->message_notification_group.last_notification_date << ", max removed "
35175                       << d->message_notification_group.max_removed_notification_id << "/"
35176                       << d->message_notification_group.max_removed_message_id << " and new secret chat "
35177                       << d->new_secret_chat_notification_id;
35178   VLOG(notifications) << "Have " << dialog_id << " with mention " << d->mention_notification_group.group_id
35179                       << " with last " << d->mention_notification_group.last_notification_id << " sent at "
35180                       << d->mention_notification_group.last_notification_date << ", max removed "
35181                       << d->mention_notification_group.max_removed_notification_id << "/"
35182                       << d->mention_notification_group.max_removed_message_id << " and pinned "
35183                       << d->pinned_message_notification_message_id;
35184   VLOG(notifications) << "In " << dialog_id << " have last_read_inbox_message_id = " << d->last_read_inbox_message_id
35185                       << ", last_new_message_id = " << d->last_new_message_id
35186                       << ", max_notification_message_id = " << d->max_notification_message_id;
35187 
35188   if (d->messages != nullptr) {
35189     CHECK(d->messages->message_id == last_message_id);
35190     CHECK(d->messages->left == nullptr);
35191     CHECK(d->messages->right == nullptr);
35192   }
35193 
35194   // must be after update_dialog_pos, because uses d->order
35195   // must be after checks that dialog has at most one message, because read_history_inbox can load
35196   // pinned message to remove its notification
35197   if (d->pending_read_channel_inbox_pts != 0 && !td_->auth_manager_->is_bot() &&
35198       have_input_peer(dialog_id, AccessRights::Read) && need_unread_counter(d->order)) {
35199     if (d->pts == d->pending_read_channel_inbox_pts) {
35200       d->pending_read_channel_inbox_pts = 0;
35201       read_history_inbox(dialog_id, d->pending_read_channel_inbox_max_message_id,
35202                          d->pending_read_channel_inbox_server_unread_count, "fix_new_dialog 12");
35203       on_dialog_updated(dialog_id, "fix_new_dialog 13");
35204     } else if (d->pts > d->pending_read_channel_inbox_pts) {
35205       d->need_repair_channel_server_unread_count = true;
35206       d->pending_read_channel_inbox_pts = 0;
35207       on_dialog_updated(dialog_id, "fix_new_dialog 14");
35208     } else {
35209       channel_get_difference_retry_timeout_.add_timeout_in(dialog_id.get(), 0.001);
35210     }
35211   } else {
35212     d->pending_read_channel_inbox_pts = 0;
35213   }
35214   if (need_get_history && !td_->auth_manager_->is_bot() && dialog_id != being_added_dialog_id_ &&
35215       dialog_id != being_added_by_new_message_dialog_id_ && have_input_peer(dialog_id, AccessRights::Read) &&
35216       (d->order != DEFAULT_ORDER || is_dialog_sponsored(d))) {
35217     get_history_from_the_end_impl(d, true, false, Auto());
35218   }
35219   if (d->need_repair_server_unread_count && need_unread_counter(d->order)) {
35220     CHECK(dialog_type != DialogType::SecretChat);
35221     repair_server_unread_count(dialog_id, d->server_unread_count);
35222   }
35223   if (d->need_repair_channel_server_unread_count) {
35224     repair_channel_server_unread_count(d);
35225   }
35226 }
35227 
add_dialog_last_database_message(Dialog * d,unique_ptr<Message> && last_database_message)35228 void MessagesManager::add_dialog_last_database_message(Dialog *d, unique_ptr<Message> &&last_database_message) {
35229   CHECK(d != nullptr);
35230   CHECK(last_database_message != nullptr);
35231   CHECK(last_database_message->left == nullptr);
35232   CHECK(last_database_message->right == nullptr);
35233 
35234   auto dialog_id = d->dialog_id;
35235   auto message_id = last_database_message->message_id;
35236   CHECK(message_id.is_valid());
35237   LOG_CHECK(d->last_database_message_id == message_id)
35238       << message_id << " " << d->last_database_message_id << " " << d->debug_set_dialog_last_database_message_id;
35239 
35240   bool need_update_dialog_pos = false;
35241   const Message *m = nullptr;
35242   if (have_input_peer(dialog_id, AccessRights::Read)) {
35243     bool need_update = false;
35244     last_database_message->have_previous = false;
35245     last_database_message->have_next = false;
35246     last_database_message->from_database = true;
35247     m = add_message_to_dialog(d, std::move(last_database_message), false, &need_update, &need_update_dialog_pos,
35248                               "add_dialog_last_database_message 1");
35249     if (need_update_dialog_pos) {
35250       LOG(ERROR) << "Need to update pos in " << dialog_id;
35251     }
35252   }
35253   if (m != nullptr) {
35254     set_dialog_last_message_id(d, m->message_id, "add_dialog_last_database_message 2");
35255     send_update_chat_last_message(d, "add_dialog_last_database_message 3");
35256   } else {
35257     if (d->pending_last_message_date != 0) {
35258       d->pending_last_message_date = 0;
35259       d->pending_last_message_id = MessageId();
35260       need_update_dialog_pos = true;
35261     }
35262     on_dialog_updated(dialog_id, "add_dialog_last_database_message 4");  // resave without last database message
35263 
35264     if (!td_->auth_manager_->is_bot() && dialog_id != being_added_dialog_id_ &&
35265         dialog_id != being_added_by_new_message_dialog_id_ && have_input_peer(dialog_id, AccessRights::Read) &&
35266         (d->order != DEFAULT_ORDER || is_dialog_sponsored(d))) {
35267       get_history_from_the_end_impl(d, true, false, Auto());
35268     }
35269   }
35270 
35271   if (need_update_dialog_pos) {
35272     update_dialog_pos(d, "add_dialog_last_database_message 5");
35273   }
35274 }
35275 
update_dialogs_hints(const Dialog * d)35276 void MessagesManager::update_dialogs_hints(const Dialog *d) {
35277   if (!td_->auth_manager_->is_bot() && d->order != DEFAULT_ORDER) {
35278     dialogs_hints_.add(-d->dialog_id.get(), get_dialog_title(d->dialog_id) + ' ' + get_dialog_username(d->dialog_id));
35279   }
35280 }
35281 
update_dialogs_hints_rating(const Dialog * d)35282 void MessagesManager::update_dialogs_hints_rating(const Dialog *d) {
35283   if (td_->auth_manager_->is_bot()) {
35284     return;
35285   }
35286   if (d->order == DEFAULT_ORDER) {
35287     LOG(INFO) << "Remove " << d->dialog_id << " from chats search";
35288     dialogs_hints_.remove(-d->dialog_id.get());
35289   } else {
35290     LOG(INFO) << "Change position of " << d->dialog_id << " in chats search";
35291     dialogs_hints_.set_rating(-d->dialog_id.get(), -get_dialog_base_order(d));
35292   }
35293 }
35294 
get_dialog_order(MessageId message_id,int32 message_date)35295 int64 MessagesManager::get_dialog_order(MessageId message_id, int32 message_date) {
35296   CHECK(!message_id.is_scheduled());
35297   return (static_cast<int64>(message_date) << 32) +
35298          message_id.get_prev_server_message_id().get_server_message_id().get();
35299 }
35300 
is_dialog_sponsored(const Dialog * d) const35301 bool MessagesManager::is_dialog_sponsored(const Dialog *d) const {
35302   return d->order == DEFAULT_ORDER && d->dialog_id == sponsored_dialog_id_;
35303 }
35304 
get_dialog_base_order(const Dialog * d) const35305 int64 MessagesManager::get_dialog_base_order(const Dialog *d) const {
35306   if (td_->auth_manager_->is_bot()) {
35307     return 0;  // to not call get_dialog_list
35308   }
35309   if (is_dialog_sponsored(d)) {
35310     return SPONSORED_DIALOG_ORDER;
35311   }
35312   if (d->order == DEFAULT_ORDER) {
35313     return 0;
35314   }
35315   auto pinned_order = get_dialog_pinned_order(DialogListId(FolderId::main()), d->dialog_id);
35316   if (pinned_order != DEFAULT_ORDER) {
35317     return pinned_order;
35318   }
35319   return d->order;
35320 }
35321 
get_dialog_private_order(const DialogList * list,const Dialog * d) const35322 int64 MessagesManager::get_dialog_private_order(const DialogList *list, const Dialog *d) const {
35323   if (list == nullptr || td_->auth_manager_->is_bot()) {
35324     return 0;
35325   }
35326 
35327   if (is_dialog_sponsored(d) && list->dialog_list_id == DialogListId(FolderId::main())) {
35328     return SPONSORED_DIALOG_ORDER;
35329   }
35330   if (d->order == DEFAULT_ORDER) {
35331     return 0;
35332   }
35333   auto pinned_order = get_dialog_pinned_order(list, d->dialog_id);
35334   if (pinned_order != DEFAULT_ORDER) {
35335     return pinned_order;
35336   }
35337   return d->order;
35338 }
35339 
get_chat_position_object(DialogListId dialog_list_id,const Dialog * d) const35340 td_api::object_ptr<td_api::chatPosition> MessagesManager::get_chat_position_object(DialogListId dialog_list_id,
35341                                                                                    const Dialog *d) const {
35342   if (td_->auth_manager_->is_bot()) {
35343     return nullptr;
35344   }
35345 
35346   auto *list = get_dialog_list(dialog_list_id);
35347   if (list == nullptr) {
35348     return nullptr;
35349   }
35350 
35351   auto position = get_dialog_position_in_list(list, d);
35352   if (position.public_order == 0) {
35353     return nullptr;
35354   }
35355 
35356   auto chat_source = position.is_sponsored ? sponsored_dialog_source_.get_chat_source_object() : nullptr;
35357   return td_api::make_object<td_api::chatPosition>(dialog_list_id.get_chat_list_object(), position.public_order,
35358                                                    position.is_pinned, std::move(chat_source));
35359 }
35360 
get_chat_positions_object(const Dialog * d) const35361 vector<td_api::object_ptr<td_api::chatPosition>> MessagesManager::get_chat_positions_object(const Dialog *d) const {
35362   vector<td_api::object_ptr<td_api::chatPosition>> positions;
35363   if (!td_->auth_manager_->is_bot()) {
35364     for (auto dialog_list_id : get_dialog_list_ids(d)) {
35365       auto position = get_chat_position_object(dialog_list_id, d);
35366       if (position != nullptr) {
35367         positions.push_back(std::move(position));
35368       }
35369     }
35370     if (is_dialog_sponsored(d)) {
35371       CHECK(positions.empty());
35372       positions.push_back(get_chat_position_object(DialogListId(FolderId::main()), d));
35373     }
35374   }
35375   return positions;
35376 }
35377 
get_next_pinned_dialog_order()35378 int64 MessagesManager::get_next_pinned_dialog_order() {
35379   current_pinned_dialog_order_++;
35380   LOG(INFO) << "Assign pinned_order = " << current_pinned_dialog_order_;
35381   return current_pinned_dialog_order_;
35382 }
35383 
is_removed_from_dialog_list(const Dialog * d) const35384 bool MessagesManager::is_removed_from_dialog_list(const Dialog *d) const {
35385   switch (d->dialog_id.get_type()) {
35386     case DialogType::User:
35387       break;
35388     case DialogType::Chat:
35389       return !td_->contacts_manager_->get_chat_is_active(d->dialog_id.get_chat_id());
35390     case DialogType::Channel:
35391       return !td_->contacts_manager_->get_channel_status(d->dialog_id.get_channel_id()).is_member();
35392     case DialogType::SecretChat:
35393       break;
35394     case DialogType::None:
35395     default:
35396       UNREACHABLE();
35397       break;
35398   }
35399   return false;
35400 }
35401 
update_dialog_pos(Dialog * d,const char * source,bool need_send_update,bool is_loaded_from_database)35402 void MessagesManager::update_dialog_pos(Dialog *d, const char *source, bool need_send_update,
35403                                         bool is_loaded_from_database) {
35404   if (td_->auth_manager_->is_bot()) {
35405     return;
35406   }
35407 
35408   CHECK(d != nullptr);
35409   LOG(INFO) << "Trying to update " << d->dialog_id << " order from " << source;
35410 
35411   int64 new_order = DEFAULT_ORDER;
35412   if (!is_removed_from_dialog_list(d)) {
35413     if (d->last_message_id != MessageId()) {
35414       auto m = get_message(d, d->last_message_id);
35415       CHECK(m != nullptr);
35416       LOG(INFO) << "Last message at " << m->date << " found";
35417       int64 last_message_order = get_dialog_order(m->message_id, m->date);
35418       if (last_message_order > new_order) {
35419         new_order = last_message_order;
35420       }
35421     } else if (d->delete_last_message_date > 0) {
35422       LOG(INFO) << "Deleted last " << d->deleted_last_message_id << " at " << d->delete_last_message_date << " found";
35423       int64 delete_order = get_dialog_order(d->deleted_last_message_id, d->delete_last_message_date);
35424       if (delete_order > new_order) {
35425         new_order = delete_order;
35426       }
35427     } else if (d->last_clear_history_date > 0) {
35428       LOG(INFO) << "Clear history at " << d->last_clear_history_date << " found";
35429       int64 clear_order = get_dialog_order(d->last_clear_history_message_id, d->last_clear_history_date);
35430       if (clear_order > new_order) {
35431         new_order = clear_order;
35432       }
35433     }
35434     if (d->pending_last_message_date > 0) {
35435       LOG(INFO) << "Pending last " << d->pending_last_message_id << " at " << d->pending_last_message_date << " found";
35436       int64 pending_order = get_dialog_order(d->pending_last_message_id, d->pending_last_message_date);
35437       if (pending_order > new_order) {
35438         new_order = pending_order;
35439       }
35440     }
35441     if (d->draft_message != nullptr && can_send_message(d->dialog_id).is_ok()) {
35442       LOG(INFO) << "Draft message at " << d->draft_message->date << " found";
35443       int64 draft_order = get_dialog_order(MessageId(), d->draft_message->date);
35444       if (draft_order > new_order) {
35445         new_order = draft_order;
35446       }
35447     }
35448     auto dialog_type = d->dialog_id.get_type();
35449     if (dialog_type == DialogType::Channel) {
35450       auto date = td_->contacts_manager_->get_channel_date(d->dialog_id.get_channel_id());
35451       LOG(INFO) << "Join of channel at " << date << " found";
35452       int64 join_order = get_dialog_order(MessageId(), date);
35453       if (join_order > new_order) {
35454         new_order = join_order;
35455       }
35456     }
35457     if (dialog_type == DialogType::SecretChat) {
35458       auto date = td_->contacts_manager_->get_secret_chat_date(d->dialog_id.get_secret_chat_id());
35459       if (date != 0 && !is_deleted_secret_chat(d)) {
35460         LOG(INFO) << "Creation of secret chat at " << date << " found";
35461         int64 creation_order = get_dialog_order(MessageId(), date);
35462         if (creation_order > new_order) {
35463           new_order = creation_order;
35464         }
35465       }
35466     }
35467     if (new_order == DEFAULT_ORDER && !d->is_empty) {
35468       LOG(INFO) << "There are no known messages in the chat, just leave it where it is";
35469       new_order = d->order;
35470     }
35471   }
35472 
35473   if (set_dialog_order(d, new_order, need_send_update, is_loaded_from_database, source)) {
35474     on_dialog_updated(d->dialog_id, "update_dialog_pos");
35475   }
35476 }
35477 
set_dialog_order(Dialog * d,int64 new_order,bool need_send_update,bool is_loaded_from_database,const char * source)35478 bool MessagesManager::set_dialog_order(Dialog *d, int64 new_order, bool need_send_update, bool is_loaded_from_database,
35479                                        const char *source) {
35480   if (td_->auth_manager_->is_bot()) {
35481     return false;
35482   }
35483 
35484   CHECK(d != nullptr);
35485   DialogId dialog_id = d->dialog_id;
35486   DialogDate old_date(d->order, dialog_id);
35487   DialogDate new_date(new_order, dialog_id);
35488 
35489   if (old_date == new_date) {
35490     LOG(INFO) << "Order of " << d->dialog_id << " from " << d->folder_id << " is still " << new_order << " from "
35491               << source;
35492   } else {
35493     LOG(INFO) << "Update order of " << dialog_id << " from " << d->folder_id << " from " << d->order << " to "
35494               << new_order << " from " << source;
35495   }
35496 
35497   auto folder_ptr = get_dialog_folder(d->folder_id);
35498   LOG_CHECK(folder_ptr != nullptr) << is_inited_ << ' ' << G()->close_flag() << ' ' << dialog_id << ' ' << d->folder_id
35499                                    << ' ' << is_loaded_from_database << ' ' << td_->auth_manager_->is_authorized()
35500                                    << ' ' << td_->auth_manager_->was_authorized() << ' ' << source;
35501   auto &folder = *folder_ptr;
35502   if (old_date == new_date) {
35503     if (new_order == DEFAULT_ORDER) {
35504       // first addition of a new left dialog
35505       if (folder.ordered_dialogs_.insert(new_date).second) {
35506         for (const auto &dialog_list : dialog_lists_) {
35507           if (get_dialog_pinned_order(&dialog_list.second, d->dialog_id) != DEFAULT_ORDER) {
35508             set_dialog_is_pinned(dialog_list.first, d, false);
35509           }
35510         }
35511       }
35512     }
35513 
35514     return false;
35515   }
35516 
35517   auto dialog_positions = get_dialog_positions(d);
35518 
35519   if (folder.ordered_dialogs_.erase(old_date) == 0) {
35520     LOG_IF(ERROR, d->order != DEFAULT_ORDER) << dialog_id << " not found in the chat list from " << source;
35521   }
35522 
35523   folder.ordered_dialogs_.insert(new_date);
35524 
35525   bool is_added = (d->order == DEFAULT_ORDER);
35526   bool is_removed = (new_order == DEFAULT_ORDER);
35527 
35528   d->order = new_order;
35529 
35530   if (is_added) {
35531     update_dialogs_hints(d);
35532   }
35533   update_dialogs_hints_rating(d);
35534 
35535   update_dialog_lists(d, std::move(dialog_positions), need_send_update, is_loaded_from_database, source);
35536 
35537   if (!is_loaded_from_database) {
35538     auto dialog_type = dialog_id.get_type();
35539     if (dialog_type == DialogType::Channel && is_added && being_added_dialog_id_ != dialog_id) {
35540       repair_channel_server_unread_count(d);
35541       LOG(INFO) << "Schedule getDifference in " << dialog_id.get_channel_id();
35542       channel_get_difference_retry_timeout_.add_timeout_in(dialog_id.get(), 0.001);
35543     }
35544     if (dialog_type == DialogType::Channel && is_removed) {
35545       remove_all_dialog_notifications(d, false, source);
35546       remove_all_dialog_notifications(d, true, source);
35547       clear_active_dialog_actions(dialog_id);
35548     }
35549   }
35550 
35551   return true;
35552 }
35553 
update_dialog_lists(Dialog * d,std::unordered_map<DialogListId,DialogPositionInList,DialogListIdHash> && old_positions,bool need_send_update,bool is_loaded_from_database,const char * source)35554 void MessagesManager::update_dialog_lists(
35555     Dialog *d, std::unordered_map<DialogListId, DialogPositionInList, DialogListIdHash> &&old_positions,
35556     bool need_send_update, bool is_loaded_from_database, const char *source) {
35557   if (td_->auth_manager_->is_bot()) {
35558     return;
35559   }
35560 
35561   CHECK(d != nullptr);
35562   auto dialog_id = d->dialog_id;
35563   if (being_added_dialog_id_ == dialog_id) {
35564     // do not try to update dialog lists, while the dialog isn't inited
35565     return;
35566   }
35567 
35568   LOG(INFO) << "Update lists of " << dialog_id << " from " << source;
35569 
35570   if (d->order == DEFAULT_ORDER) {
35571     for (auto &old_position : old_positions) {
35572       if (old_position.second.is_pinned) {
35573         set_dialog_is_pinned(old_position.first, d, false, false);
35574       }
35575     }
35576 
35577     if (d->folder_id != FolderId::main()) {
35578       LOG(INFO) << "Change folder of " << dialog_id << " to " << FolderId::main();
35579       DialogDate dialog_date(d->order, dialog_id);
35580       get_dialog_folder(d->folder_id)->ordered_dialogs_.erase(dialog_date);
35581       do_set_dialog_folder_id(d, FolderId::main());
35582       get_dialog_folder(d->folder_id)->ordered_dialogs_.insert(dialog_date);
35583     }
35584   }
35585 
35586   for (auto &dialog_list : dialog_lists_) {
35587     auto dialog_list_id = dialog_list.first;
35588     auto &list = dialog_list.second;
35589 
35590     const DialogPositionInList &old_position = old_positions[dialog_list_id];
35591     const DialogPositionInList new_position = get_dialog_position_in_list(&list, d, true);
35592 
35593     // sponsored chat is never "in list"
35594     bool was_in_list = old_position.order != DEFAULT_ORDER && old_position.private_order != 0;
35595     bool is_in_list = new_position.order != DEFAULT_ORDER && new_position.private_order != 0;
35596     CHECK(was_in_list == is_dialog_in_list(d, dialog_list_id));
35597 
35598     LOG(DEBUG) << "Update position of " << dialog_id << " in " << dialog_list_id << " from " << old_position << " to "
35599                << new_position;
35600 
35601     bool need_update_unread_chat_count = false;
35602     if (was_in_list != is_in_list) {
35603       const int32 delta = was_in_list ? -1 : 1;
35604       list.in_memory_dialog_total_count_ += delta;
35605       if (!is_loaded_from_database) {
35606         int32 &total_count = dialog_id.get_type() == DialogType::SecretChat ? list.secret_chat_total_count_
35607                                                                             : list.server_dialog_total_count_;
35608         if (total_count != -1) {
35609           total_count += delta;
35610           if (total_count < 0) {
35611             LOG(ERROR) << "Total chat count became negative after leaving " << dialog_id;
35612             total_count = 0;
35613           }
35614         }
35615       }
35616 
35617       if (!is_loaded_from_database) {
35618         need_update_unread_chat_count =
35619             list.is_dialog_unread_count_inited_ && old_position.total_dialog_count != get_dialog_total_count(list);
35620         auto unread_count = d->server_unread_count + d->local_unread_count;
35621         const char *change_source = was_in_list ? "on_dialog_leave" : "on_dialog_join";
35622         if (unread_count != 0 && list.is_message_unread_count_inited_) {
35623           unread_count *= delta;
35624 
35625           list.unread_message_total_count_ += unread_count;
35626           if (is_dialog_muted(d)) {
35627             list.unread_message_muted_count_ += unread_count;
35628           }
35629           send_update_unread_message_count(list, dialog_id, true, change_source);
35630         }
35631         if ((unread_count != 0 || d->is_marked_as_unread) && list.is_dialog_unread_count_inited_) {
35632           list.unread_dialog_total_count_ += delta;
35633           if (unread_count == 0 && d->is_marked_as_unread) {
35634             list.unread_dialog_marked_count_ += delta;
35635           }
35636           if (is_dialog_muted(d)) {
35637             list.unread_dialog_muted_count_ += delta;
35638             if (unread_count == 0 && d->is_marked_as_unread) {
35639               list.unread_dialog_muted_marked_count_ += delta;
35640             }
35641           }
35642           need_update_unread_chat_count = true;
35643         }
35644         if (need_update_unread_chat_count) {
35645           send_update_unread_chat_count(list, dialog_id, true, change_source);
35646         }
35647       }
35648 
35649       if (was_in_list) {
35650         remove_dialog_from_list(d, dialog_list_id);
35651       } else {
35652         add_dialog_to_list(d, dialog_list_id);
35653       }
35654     }
35655     if (!need_update_unread_chat_count && list.is_dialog_unread_count_inited_ &&
35656         old_position.total_dialog_count != get_dialog_total_count(list)) {
35657       send_update_unread_chat_count(list, dialog_id, true, "changed total count");
35658     }
35659 
35660     if (need_send_update && need_send_update_chat_position(old_position, new_position)) {
35661       send_update_chat_position(dialog_list_id, d, source);
35662     }
35663 
35664     if (!is_loaded_from_database && !old_position.is_sponsored && new_position.is_sponsored) {
35665       // a chat is sponsored only if user isn't a chat member
35666       remove_all_dialog_notifications(d, false, "update_dialog_lists 3");
35667       remove_all_dialog_notifications(d, true, "update_dialog_lists 4");
35668     }
35669   }
35670 }
35671 
update_last_dialog_date(FolderId folder_id)35672 void MessagesManager::update_last_dialog_date(FolderId folder_id) {
35673   CHECK(!td_->auth_manager_->is_bot());
35674   auto *folder = get_dialog_folder(folder_id);
35675   CHECK(folder != nullptr);
35676   auto old_last_dialog_date = folder->folder_last_dialog_date_;
35677   folder->folder_last_dialog_date_ = folder->last_server_dialog_date_;
35678   CHECK(old_last_dialog_date <= folder->folder_last_dialog_date_);
35679 
35680   LOG(INFO) << "Update last dialog date in " << folder_id << " from " << old_last_dialog_date << " to "
35681             << folder->folder_last_dialog_date_;
35682   LOG(INFO) << "Know about " << folder->ordered_dialogs_.size() << " chats";
35683 
35684   if (old_last_dialog_date != folder->folder_last_dialog_date_) {
35685     for (auto &dialog_list : dialog_lists_) {
35686       update_list_last_pinned_dialog_date(dialog_list.second);
35687       update_list_last_dialog_date(dialog_list.second);
35688     }
35689   }
35690 
35691   if (G()->parameters().use_message_db &&
35692       folder->last_database_server_dialog_date_ < folder->last_server_dialog_date_) {
35693     auto last_server_dialog_date_string = PSTRING() << folder->last_server_dialog_date_.get_order() << ' '
35694                                                     << folder->last_server_dialog_date_.get_dialog_id().get();
35695     G()->td_db()->get_binlog_pmc()->set(PSTRING() << "last_server_dialog_date" << folder_id.get(),
35696                                         last_server_dialog_date_string);
35697     LOG(INFO) << "Save last server dialog date " << folder->last_server_dialog_date_;
35698     folder->last_database_server_dialog_date_ = folder->last_server_dialog_date_;
35699     folder->last_loaded_database_dialog_date_ = folder->last_server_dialog_date_;
35700   }
35701 }
35702 
35703 // must not call get_dialog_filter
do_update_list_last_pinned_dialog_date(DialogList & list) const35704 bool MessagesManager::do_update_list_last_pinned_dialog_date(DialogList &list) const {
35705   CHECK(!td_->auth_manager_->is_bot());
35706   if (list.last_pinned_dialog_date_ == MAX_DIALOG_DATE) {
35707     return false;
35708   }
35709   if (!list.are_pinned_dialogs_inited_) {
35710     return false;
35711   }
35712 
35713   DialogDate max_dialog_date = MIN_DIALOG_DATE;
35714   for (auto &pinned_dialog : list.pinned_dialogs_) {
35715     if (!have_dialog(pinned_dialog.get_dialog_id())) {
35716       break;
35717     }
35718 
35719     max_dialog_date = pinned_dialog;
35720   }
35721   if (list.pinned_dialogs_.empty() || max_dialog_date == list.pinned_dialogs_.back()) {
35722     max_dialog_date = MAX_DIALOG_DATE;
35723   }
35724   if (list.last_pinned_dialog_date_ < max_dialog_date) {
35725     LOG(INFO) << "Update last pinned dialog date in " << list.dialog_list_id << " from "
35726               << list.last_pinned_dialog_date_ << " to " << max_dialog_date;
35727     list.last_pinned_dialog_date_ = max_dialog_date;
35728     return true;
35729   }
35730   return false;
35731 }
35732 
update_list_last_pinned_dialog_date(DialogList & list)35733 void MessagesManager::update_list_last_pinned_dialog_date(DialogList &list) {
35734   CHECK(!td_->auth_manager_->is_bot());
35735   if (do_update_list_last_pinned_dialog_date(list)) {
35736     update_list_last_dialog_date(list);
35737   }
35738 }
35739 
35740 // must not call get_dialog_filter
do_update_list_last_dialog_date(DialogList & list,const vector<FolderId> & folder_ids) const35741 bool MessagesManager::do_update_list_last_dialog_date(DialogList &list, const vector<FolderId> &folder_ids) const {
35742   CHECK(!td_->auth_manager_->is_bot());
35743   auto new_last_dialog_date = list.last_pinned_dialog_date_;
35744   for (auto folder_id : folder_ids) {
35745     const auto &folder = *get_dialog_folder(folder_id);
35746     if (folder.folder_last_dialog_date_ < new_last_dialog_date) {
35747       new_last_dialog_date = folder.folder_last_dialog_date_;
35748     }
35749   }
35750 
35751   if (list.list_last_dialog_date_ != new_last_dialog_date) {
35752     auto old_last_dialog_date = list.list_last_dialog_date_;
35753     LOG(INFO) << "Update last dialog date in " << list.dialog_list_id << " from " << old_last_dialog_date << " to "
35754               << new_last_dialog_date;
35755     LOG_CHECK(old_last_dialog_date < new_last_dialog_date)
35756         << list.dialog_list_id << " " << old_last_dialog_date << " " << new_last_dialog_date << " "
35757         << get_dialog_list_folder_ids(list) << " " << list.last_pinned_dialog_date_ << " "
35758         << get_dialog_folder(FolderId::main())->folder_last_dialog_date_ << " "
35759         << get_dialog_folder(FolderId::archive())->folder_last_dialog_date_ << " " << list.load_list_queries_.size()
35760         << " " << list.pinned_dialogs_;
35761     list.list_last_dialog_date_ = new_last_dialog_date;
35762     return true;
35763   }
35764   return false;
35765 }
35766 
update_list_last_dialog_date(DialogList & list)35767 void MessagesManager::update_list_last_dialog_date(DialogList &list) {
35768   CHECK(!td_->auth_manager_->is_bot());
35769   auto old_dialog_total_count = get_dialog_total_count(list);
35770   auto old_last_dialog_date = list.list_last_dialog_date_;
35771   if (!do_update_list_last_dialog_date(list, get_dialog_list_folder_ids(list))) {
35772     LOG(INFO) << "Don't need to update last dialog date in " << list.dialog_list_id;
35773     return;
35774   }
35775 
35776   for (auto it = std::upper_bound(list.pinned_dialogs_.begin(), list.pinned_dialogs_.end(), old_last_dialog_date);
35777        it != list.pinned_dialogs_.end() && *it <= list.list_last_dialog_date_; ++it) {
35778     auto dialog_id = it->get_dialog_id();
35779     auto d = get_dialog(dialog_id);
35780     CHECK(d != nullptr);
35781     send_update_chat_position(list.dialog_list_id, d, "update_list_last_dialog_date");
35782   }
35783 
35784   bool is_list_further_loaded = list.list_last_dialog_date_ == MAX_DIALOG_DATE;
35785   for (auto folder_id : get_dialog_list_folder_ids(list)) {
35786     const auto &folder = *get_dialog_folder(folder_id);
35787     for (auto it = folder.ordered_dialogs_.upper_bound(old_last_dialog_date);
35788          it != folder.ordered_dialogs_.end() && *it <= folder.folder_last_dialog_date_; ++it) {
35789       if (it->get_order() == DEFAULT_ORDER) {
35790         break;
35791       }
35792       auto dialog_id = it->get_dialog_id();
35793       if (get_dialog_pinned_order(&list, dialog_id) == DEFAULT_ORDER) {
35794         auto d = get_dialog(dialog_id);
35795         CHECK(d != nullptr);
35796         if (is_dialog_in_list(d, list.dialog_list_id)) {
35797           send_update_chat_position(list.dialog_list_id, d, "update_list_last_dialog_date 2");
35798           is_list_further_loaded = true;
35799         }
35800       }
35801     }
35802   }
35803 
35804   if (list.list_last_dialog_date_ == MAX_DIALOG_DATE) {
35805     recalc_unread_count(list.dialog_list_id, old_dialog_total_count, true);
35806   }
35807 
35808   LOG(INFO) << "After updating last dialog date in " << list.dialog_list_id << " to " << list.list_last_dialog_date_
35809             << " have is_list_further_loaded == " << is_list_further_loaded << " and " << list.load_list_queries_.size()
35810             << " pending load list queries";
35811   if (is_list_further_loaded && !list.load_list_queries_.empty()) {
35812     auto promises = std::move(list.load_list_queries_);
35813     list.load_list_queries_.clear();
35814     for (auto &promise : promises) {
35815       promise.set_value(Unit());
35816     }
35817   }
35818 }
35819 
get_sequence_dispatcher_id(DialogId dialog_id,MessageContentType message_content_type)35820 uint64 MessagesManager::get_sequence_dispatcher_id(DialogId dialog_id, MessageContentType message_content_type) {
35821   switch (message_content_type) {
35822     case MessageContentType::Animation:
35823     case MessageContentType::Audio:
35824     case MessageContentType::Document:
35825     case MessageContentType::Photo:
35826     case MessageContentType::Sticker:
35827     case MessageContentType::Video:
35828     case MessageContentType::VideoNote:
35829     case MessageContentType::VoiceNote:
35830       return static_cast<uint64>(dialog_id.get() * 2 + 1);
35831     default:
35832       return static_cast<uint64>(dialog_id.get() * 2 + 2);
35833   }
35834 }
35835 
get_dialog(DialogId dialog_id)35836 MessagesManager::Dialog *MessagesManager::get_dialog(DialogId dialog_id) {
35837   auto it = dialogs_.find(dialog_id);
35838   return it == dialogs_.end() ? nullptr : it->second.get();
35839 }
35840 
get_dialog(DialogId dialog_id) const35841 const MessagesManager::Dialog *MessagesManager::get_dialog(DialogId dialog_id) const {
35842   auto it = dialogs_.find(dialog_id);
35843   return it == dialogs_.end() ? nullptr : it->second.get();
35844 }
35845 
have_dialog_force(DialogId dialog_id,const char * source)35846 bool MessagesManager::have_dialog_force(DialogId dialog_id, const char *source) {
35847   return loaded_dialogs_.count(dialog_id) > 0 || get_dialog_force(dialog_id, source) != nullptr;
35848 }
35849 
get_dialog_force(DialogId dialog_id,const char * source)35850 MessagesManager::Dialog *MessagesManager::get_dialog_force(DialogId dialog_id, const char *source) {
35851   init();
35852 
35853   auto it = dialogs_.find(dialog_id);
35854   if (it != dialogs_.end()) {
35855     Dialog *d = it->second.get();
35856     LOG_CHECK(d->dialog_id == dialog_id) << d->dialog_id << ' ' << dialog_id;
35857     return d;
35858   }
35859 
35860   if (!dialog_id.is_valid() || !G()->parameters().use_message_db || loaded_dialogs_.count(dialog_id) > 0) {
35861     return nullptr;
35862   }
35863 
35864   auto r_value = G()->td_db()->get_dialog_db_sync()->get_dialog(dialog_id);
35865   if (r_value.is_ok()) {
35866     LOG(INFO) << "Loaded " << dialog_id << " from database from " << source;
35867     auto d = on_load_dialog_from_database(dialog_id, r_value.move_as_ok(), source);
35868     LOG_CHECK(d == nullptr || d->dialog_id == dialog_id) << d->dialog_id << ' ' << dialog_id;
35869     return d;
35870   } else {
35871     LOG(INFO) << "Failed to load " << dialog_id << " from database from " << source << ": "
35872               << r_value.error().message();
35873     return nullptr;
35874   }
35875 }
35876 
parse_dialog(DialogId dialog_id,const BufferSlice & value,const char * source)35877 unique_ptr<MessagesManager::Dialog> MessagesManager::parse_dialog(DialogId dialog_id, const BufferSlice &value,
35878                                                                   const char *source) {
35879   LOG(INFO) << "Loaded " << dialog_id << " of size " << value.size() << " from database from " << source;
35880   auto d = make_unique<Dialog>();
35881   d->dialog_id = dialog_id;
35882   invalidate_message_indexes(d.get());  // must initialize indexes, because some of them could be not parsed
35883 
35884   loaded_dialogs_.insert(dialog_id);
35885 
35886   auto status = log_event_parse(*d, value.as_slice());
35887   if (status.is_error() || !d->dialog_id.is_valid() || d->dialog_id != dialog_id) {
35888     // can't happen unless database is broken, but has been seen in the wild
35889     // if dialog_id is invalid, we can't repair the dialog
35890     LOG_CHECK(dialog_id.is_valid()) << "Can't repair " << dialog_id << ' ' << d->dialog_id << ' ' << status << ' '
35891                                     << source << ' ' << format::as_hex_dump<4>(value.as_slice());
35892 
35893     LOG(ERROR) << "Repair broken " << dialog_id << ' ' << format::as_hex_dump<4>(value.as_slice());
35894 
35895     // just clean all known data about the dialog
35896     d = make_unique<Dialog>();
35897     d->dialog_id = dialog_id;
35898     invalidate_message_indexes(d.get());
35899 
35900     // and try to reget it from the server if possible
35901     have_dialog_info_force(dialog_id);
35902     if (have_input_peer(dialog_id, AccessRights::Read)) {
35903       if (dialog_id.get_type() != DialogType::SecretChat) {
35904         send_get_dialog_query(dialog_id, Auto(), 0, source);
35905       }
35906     } else {
35907       LOG(ERROR) << "Have no info about " << dialog_id << " from " << source << " to repair it";
35908     }
35909   }
35910   CHECK(dialog_id == d->dialog_id);
35911 
35912   Dependencies dependencies;
35913   add_dialog_dependencies(dependencies, dialog_id);
35914   if (d->default_join_group_call_as_dialog_id != dialog_id) {
35915     add_message_sender_dependencies(dependencies, d->default_join_group_call_as_dialog_id);
35916   }
35917   if (d->default_send_message_as_dialog_id != dialog_id) {
35918     add_message_sender_dependencies(dependencies, d->default_send_message_as_dialog_id);
35919   }
35920   if (d->messages != nullptr) {
35921     add_message_dependencies(dependencies, d->messages.get());
35922   }
35923   if (d->draft_message != nullptr) {
35924     add_formatted_text_dependencies(dependencies, &d->draft_message->input_message_text.text);
35925   }
35926   for (auto user_id : d->pending_join_request_user_ids) {
35927     dependencies.user_ids.insert(user_id);
35928   }
35929   if (!resolve_dependencies_force(td_, dependencies, source)) {
35930     send_get_dialog_query(dialog_id, Auto(), 0, source);
35931   }
35932 
35933   return d;
35934 }
35935 
on_load_dialog_from_database(DialogId dialog_id,BufferSlice && value,const char * source)35936 MessagesManager::Dialog *MessagesManager::on_load_dialog_from_database(DialogId dialog_id, BufferSlice &&value,
35937                                                                        const char *source) {
35938   CHECK(G()->parameters().use_message_db);
35939 
35940   if (!dialog_id.is_valid()) {
35941     // hack
35942     LogEventParser dialog_id_parser(value.as_slice());
35943     int32 flags;
35944     parse(flags, dialog_id_parser);
35945     parse(dialog_id, dialog_id_parser);
35946 
35947     if (!dialog_id.is_valid()) {
35948       LOG(ERROR) << "Failed to parse dialog_id from blob. Database is broken";
35949       return nullptr;
35950     }
35951   }
35952 
35953   auto old_d = get_dialog(dialog_id);
35954   if (old_d != nullptr) {
35955     return old_d;
35956   }
35957 
35958   LOG(INFO) << "Add new " << dialog_id << " from database from " << source;
35959   return add_new_dialog(parse_dialog(dialog_id, value, source), true, source);
35960 }
35961 
get_server_dialog_filter(DialogFilterId dialog_filter_id) const35962 const DialogFilter *MessagesManager::get_server_dialog_filter(DialogFilterId dialog_filter_id) const {
35963   CHECK(!disable_get_dialog_filter_);
35964   for (const auto &filter : server_dialog_filters_) {
35965     if (filter->dialog_filter_id == dialog_filter_id) {
35966       return filter.get();
35967     }
35968   }
35969   return nullptr;
35970 }
35971 
get_dialog_filter(DialogFilterId dialog_filter_id)35972 DialogFilter *MessagesManager::get_dialog_filter(DialogFilterId dialog_filter_id) {
35973   CHECK(!disable_get_dialog_filter_);
35974   for (auto &filter : dialog_filters_) {
35975     if (filter->dialog_filter_id == dialog_filter_id) {
35976       return filter.get();
35977     }
35978   }
35979   return nullptr;
35980 }
35981 
get_dialog_filter(DialogFilterId dialog_filter_id) const35982 const DialogFilter *MessagesManager::get_dialog_filter(DialogFilterId dialog_filter_id) const {
35983   CHECK(!disable_get_dialog_filter_);
35984   for (const auto &filter : dialog_filters_) {
35985     if (filter->dialog_filter_id == dialog_filter_id) {
35986       return filter.get();
35987     }
35988   }
35989   return nullptr;
35990 }
35991 
get_dialog_filter_ids(const vector<unique_ptr<DialogFilter>> & dialog_filters)35992 vector<DialogFilterId> MessagesManager::get_dialog_filter_ids(const vector<unique_ptr<DialogFilter>> &dialog_filters) {
35993   return transform(dialog_filters, [](const auto &dialog_filter) { return dialog_filter->dialog_filter_id; });
35994 }
35995 
get_dialog_filter_folder_ids(const DialogFilter * filter)35996 vector<FolderId> MessagesManager::get_dialog_filter_folder_ids(const DialogFilter *filter) {
35997   CHECK(filter != nullptr);
35998   if (filter->exclude_archived && filter->pinned_dialog_ids.empty() && filter->included_dialog_ids.empty()) {
35999     return {FolderId::main()};
36000   }
36001   return {FolderId::main(), FolderId::archive()};
36002 }
36003 
get_dialog_list_folder_ids(const DialogList & list) const36004 vector<FolderId> MessagesManager::get_dialog_list_folder_ids(const DialogList &list) const {
36005   CHECK(!td_->auth_manager_->is_bot());
36006   if (list.dialog_list_id.is_folder()) {
36007     return {list.dialog_list_id.get_folder_id()};
36008   }
36009   if (list.dialog_list_id.is_filter()) {
36010     auto dialog_filter_id = list.dialog_list_id.get_filter_id();
36011     return get_dialog_filter_folder_ids(get_dialog_filter(dialog_filter_id));
36012   }
36013   UNREACHABLE();
36014   return {};
36015 }
36016 
has_dialogs_from_folder(const DialogList & list,const DialogFolder & folder) const36017 bool MessagesManager::has_dialogs_from_folder(const DialogList &list, const DialogFolder &folder) const {
36018   CHECK(!td_->auth_manager_->is_bot());
36019   if (list.dialog_list_id.is_folder()) {
36020     return list.dialog_list_id.get_folder_id() == folder.folder_id;
36021   }
36022   if (list.dialog_list_id.is_filter()) {
36023     auto dialog_filter_id = list.dialog_list_id.get_filter_id();
36024     auto *filter = get_dialog_filter(dialog_filter_id);
36025     CHECK(filter != nullptr);
36026     if (filter->exclude_archived && filter->pinned_dialog_ids.empty() && filter->included_dialog_ids.empty()) {
36027       return folder.folder_id == FolderId::main();
36028     }
36029     return true;
36030   }
36031   UNREACHABLE();
36032   return false;
36033 }
36034 
is_dialog_in_list(const Dialog * d,DialogListId dialog_list_id)36035 bool MessagesManager::is_dialog_in_list(const Dialog *d, DialogListId dialog_list_id) {
36036   return td::contains(d->dialog_list_ids, dialog_list_id);
36037 }
36038 
add_dialog_to_list(Dialog * d,DialogListId dialog_list_id)36039 void MessagesManager::add_dialog_to_list(Dialog *d, DialogListId dialog_list_id) {
36040   LOG(INFO) << "Add " << d->dialog_id << " to " << dialog_list_id;
36041   CHECK(!is_dialog_in_list(d, dialog_list_id));
36042   d->dialog_list_ids.push_back(dialog_list_id);
36043 }
36044 
remove_dialog_from_list(Dialog * d,DialogListId dialog_list_id)36045 void MessagesManager::remove_dialog_from_list(Dialog *d, DialogListId dialog_list_id) {
36046   LOG(INFO) << "Remove " << d->dialog_id << " from " << dialog_list_id;
36047   bool is_removed = td::remove(d->dialog_list_ids, dialog_list_id);
36048   CHECK(is_removed);
36049 }
36050 
need_dialog_in_filter(const Dialog * d,const DialogFilter * filter) const36051 bool MessagesManager::need_dialog_in_filter(const Dialog *d, const DialogFilter *filter) const {
36052   CHECK(d != nullptr);
36053   CHECK(filter != nullptr);
36054   CHECK(d->order != DEFAULT_ORDER);
36055 
36056   if (InputDialogId::contains(filter->pinned_dialog_ids, d->dialog_id)) {
36057     return true;
36058   }
36059   if (InputDialogId::contains(filter->included_dialog_ids, d->dialog_id)) {
36060     return true;
36061   }
36062   if (InputDialogId::contains(filter->excluded_dialog_ids, d->dialog_id)) {
36063     return false;
36064   }
36065   if (d->dialog_id.get_type() == DialogType::SecretChat) {
36066     auto user_id = td_->contacts_manager_->get_secret_chat_user_id(d->dialog_id.get_secret_chat_id());
36067     if (user_id.is_valid()) {
36068       auto dialog_id = DialogId(user_id);
36069       if (InputDialogId::contains(filter->pinned_dialog_ids, dialog_id)) {
36070         return true;
36071       }
36072       if (InputDialogId::contains(filter->included_dialog_ids, dialog_id)) {
36073         return true;
36074       }
36075       if (InputDialogId::contains(filter->excluded_dialog_ids, dialog_id)) {
36076         return false;
36077       }
36078     }
36079   }
36080   if (d->unread_mention_count == 0 || is_dialog_mention_notifications_disabled(d)) {
36081     if (filter->exclude_muted && is_dialog_muted(d)) {
36082       return false;
36083     }
36084     if (filter->exclude_read && d->server_unread_count + d->local_unread_count == 0 && !d->is_marked_as_unread) {
36085       return false;
36086     }
36087   }
36088   if (filter->exclude_archived && d->folder_id == FolderId::archive()) {
36089     return false;
36090   }
36091   switch (d->dialog_id.get_type()) {
36092     case DialogType::User: {
36093       auto user_id = d->dialog_id.get_user_id();
36094       if (td_->contacts_manager_->is_user_bot(user_id)) {
36095         return filter->include_bots;
36096       }
36097       if (user_id == td_->contacts_manager_->get_my_id() || td_->contacts_manager_->is_user_contact(user_id)) {
36098         return filter->include_contacts;
36099       }
36100       return filter->include_non_contacts;
36101     }
36102     case DialogType::Chat:
36103       return filter->include_groups;
36104     case DialogType::Channel:
36105       return is_broadcast_channel(d->dialog_id) ? filter->include_channels : filter->include_groups;
36106     case DialogType::SecretChat: {
36107       auto user_id = td_->contacts_manager_->get_secret_chat_user_id(d->dialog_id.get_secret_chat_id());
36108       if (td_->contacts_manager_->is_user_bot(user_id)) {
36109         return filter->include_bots;
36110       }
36111       if (td_->contacts_manager_->is_user_contact(user_id)) {
36112         return filter->include_contacts;
36113       }
36114       return filter->include_non_contacts;
36115     }
36116     default:
36117       UNREACHABLE();
36118       return false;
36119   }
36120 }
36121 
need_dialog_in_list(const Dialog * d,const DialogList & list) const36122 bool MessagesManager::need_dialog_in_list(const Dialog *d, const DialogList &list) const {
36123   CHECK(!td_->auth_manager_->is_bot());
36124   if (d->order == DEFAULT_ORDER) {
36125     return false;
36126   }
36127   if (list.dialog_list_id.is_folder()) {
36128     return d->folder_id == list.dialog_list_id.get_folder_id();
36129   }
36130   if (list.dialog_list_id.is_filter()) {
36131     auto dialog_filter_id = list.dialog_list_id.get_filter_id();
36132     return need_dialog_in_filter(d, get_dialog_filter(dialog_filter_id));
36133   }
36134   UNREACHABLE();
36135   return false;
36136 }
36137 
need_send_update_chat_position(const DialogPositionInList & old_position,const DialogPositionInList & new_position)36138 bool MessagesManager::need_send_update_chat_position(const DialogPositionInList &old_position,
36139                                                      const DialogPositionInList &new_position) {
36140   if (old_position.public_order != new_position.public_order) {
36141     return true;
36142   }
36143   if (old_position.public_order == 0) {
36144     return false;
36145   }
36146   return old_position.is_pinned != new_position.is_pinned || old_position.is_sponsored != new_position.is_sponsored;
36147 }
36148 
get_dialog_position_in_list(const DialogList * list,const Dialog * d,bool actual) const36149 MessagesManager::DialogPositionInList MessagesManager::get_dialog_position_in_list(const DialogList *list,
36150                                                                                    const Dialog *d, bool actual) const {
36151   CHECK(!td_->auth_manager_->is_bot());
36152   CHECK(list != nullptr);
36153   CHECK(d != nullptr);
36154 
36155   DialogPositionInList position;
36156   position.order = d->order;
36157   if (is_dialog_sponsored(d) || (actual ? need_dialog_in_list(d, *list) : is_dialog_in_list(d, list->dialog_list_id))) {
36158     position.private_order = get_dialog_private_order(list, d);
36159   }
36160   if (position.private_order != 0) {
36161     position.public_order =
36162         DialogDate(position.private_order, d->dialog_id) <= list->list_last_dialog_date_ ? position.private_order : 0;
36163     position.is_pinned = get_dialog_pinned_order(list, d->dialog_id) != DEFAULT_ORDER;
36164     position.is_sponsored = is_dialog_sponsored(d);
36165   }
36166   position.total_dialog_count = get_dialog_total_count(*list);
36167   return position;
36168 }
36169 
36170 std::unordered_map<DialogListId, MessagesManager::DialogPositionInList, DialogListIdHash>
get_dialog_positions(const Dialog * d) const36171 MessagesManager::get_dialog_positions(const Dialog *d) const {
36172   CHECK(d != nullptr);
36173   std::unordered_map<DialogListId, MessagesManager::DialogPositionInList, DialogListIdHash> positions;
36174   if (!td_->auth_manager_->is_bot()) {
36175     for (const auto &dialog_list : dialog_lists_) {
36176       positions.emplace(dialog_list.first, get_dialog_position_in_list(&dialog_list.second, d));
36177     }
36178   }
36179   return positions;
36180 }
36181 
get_dialog_list_ids(const Dialog * d)36182 vector<DialogListId> MessagesManager::get_dialog_list_ids(const Dialog *d) {
36183   return d->dialog_list_ids;
36184 }
36185 
get_dialog_lists(const Dialog * d)36186 MessagesManager::DialogListView MessagesManager::get_dialog_lists(const Dialog *d) {
36187   return DialogListView(this, get_dialog_list_ids(d));
36188 }
36189 
add_dialog_list(DialogListId dialog_list_id)36190 MessagesManager::DialogList &MessagesManager::add_dialog_list(DialogListId dialog_list_id) {
36191   CHECK(!td_->auth_manager_->is_bot());
36192   if (dialog_list_id.is_folder() && dialog_list_id.get_folder_id() != FolderId::archive()) {
36193     dialog_list_id = DialogListId(FolderId::main());
36194   }
36195   if (dialog_lists_.find(dialog_list_id) == dialog_lists_.end()) {
36196     LOG(INFO) << "Create " << dialog_list_id;
36197   }
36198   auto &list = dialog_lists_[dialog_list_id];
36199   list.dialog_list_id = dialog_list_id;
36200   return list;
36201 }
36202 
get_dialog_list(DialogListId dialog_list_id)36203 MessagesManager::DialogList *MessagesManager::get_dialog_list(DialogListId dialog_list_id) {
36204   CHECK(!td_->auth_manager_->is_bot());
36205   if (dialog_list_id.is_folder() && dialog_list_id.get_folder_id() != FolderId::archive()) {
36206     dialog_list_id = DialogListId(FolderId::main());
36207   }
36208   auto it = dialog_lists_.find(dialog_list_id);
36209   if (it == dialog_lists_.end()) {
36210     return nullptr;
36211   }
36212   return &it->second;
36213 }
36214 
get_dialog_list(DialogListId dialog_list_id) const36215 const MessagesManager::DialogList *MessagesManager::get_dialog_list(DialogListId dialog_list_id) const {
36216   CHECK(!td_->auth_manager_->is_bot());
36217   if (dialog_list_id.is_folder() && dialog_list_id.get_folder_id() != FolderId::archive()) {
36218     dialog_list_id = DialogListId(FolderId::main());
36219   }
36220   auto it = dialog_lists_.find(dialog_list_id);
36221   if (it == dialog_lists_.end()) {
36222     return nullptr;
36223   }
36224   return &it->second;
36225 }
36226 
get_dialog_folder(FolderId folder_id)36227 MessagesManager::DialogFolder *MessagesManager::get_dialog_folder(FolderId folder_id) {
36228   CHECK(!td_->auth_manager_->is_bot());
36229   if (folder_id != FolderId::archive()) {
36230     folder_id = FolderId::main();
36231   }
36232   auto it = dialog_folders_.find(folder_id);
36233   if (it == dialog_folders_.end()) {
36234     return nullptr;
36235   }
36236   return &it->second;
36237 }
36238 
get_dialog_folder(FolderId folder_id) const36239 const MessagesManager::DialogFolder *MessagesManager::get_dialog_folder(FolderId folder_id) const {
36240   CHECK(!td_->auth_manager_->is_bot());
36241   if (folder_id != FolderId::archive()) {
36242     folder_id = FolderId::main();
36243   }
36244   auto it = dialog_folders_.find(folder_id);
36245   if (it == dialog_folders_.end()) {
36246     return nullptr;
36247   }
36248   return &it->second;
36249 }
36250 
load_notification_settings()36251 void MessagesManager::load_notification_settings() {
36252   if (td_->auth_manager_->is_bot()) {
36253     return;
36254   }
36255   if (!users_notification_settings_.is_synchronized) {
36256     send_get_scope_notification_settings_query(NotificationSettingsScope::Private, Promise<>());
36257   }
36258   if (!chats_notification_settings_.is_synchronized) {
36259     send_get_scope_notification_settings_query(NotificationSettingsScope::Group, Promise<>());
36260   }
36261   if (!channels_notification_settings_.is_synchronized) {
36262     send_get_scope_notification_settings_query(NotificationSettingsScope::Channel, Promise<>());
36263   }
36264 }
36265 
get_channel_pts_key(DialogId dialog_id)36266 string MessagesManager::get_channel_pts_key(DialogId dialog_id) {
36267   CHECK(dialog_id.get_type() == DialogType::Channel);
36268   auto channel_id = dialog_id.get_channel_id();
36269   return PSTRING() << "ch.p" << channel_id.get();
36270 }
36271 
load_channel_pts(DialogId dialog_id) const36272 int32 MessagesManager::load_channel_pts(DialogId dialog_id) const {
36273   if (G()->ignore_background_updates() || !have_input_peer(dialog_id, AccessRights::Read)) {
36274     G()->td_db()->get_binlog_pmc()->erase(get_channel_pts_key(dialog_id));  // just in case
36275     return 0;
36276   }
36277   auto pts = to_integer<int32>(G()->td_db()->get_binlog_pmc()->get(get_channel_pts_key(dialog_id)));
36278   LOG(INFO) << "Load " << dialog_id << " pts = " << pts;
36279   return pts;
36280 }
36281 
set_channel_pts(Dialog * d,int32 new_pts,const char * source)36282 void MessagesManager::set_channel_pts(Dialog *d, int32 new_pts, const char *source) {
36283   CHECK(d != nullptr);
36284   CHECK(d->dialog_id.get_type() == DialogType::Channel);
36285 
36286   LOG_IF(ERROR, running_get_channel_difference(d->dialog_id))
36287       << "Set pts of " << d->dialog_id << " to " << new_pts << " from " << source
36288       << " while running getChannelDifference";
36289 
36290   if (is_debug_message_op_enabled()) {
36291     d->debug_message_op.emplace_back(Dialog::MessageOp::SetPts, new_pts, source);
36292   }
36293 
36294   // TODO delete_first_messages support in channels
36295   if (new_pts == std::numeric_limits<int32>::max()) {
36296     LOG(ERROR) << "Update " << d->dialog_id << " pts to -1 from " << source;
36297     G()->td_db()->get_binlog_pmc()->erase(get_channel_pts_key(d->dialog_id));
36298     d->pts = std::numeric_limits<int32>::max();
36299     if (d->pending_read_channel_inbox_pts != 0) {
36300       d->pending_read_channel_inbox_pts = 0;
36301     }
36302     return;
36303   }
36304   if (new_pts > d->pts || (0 < new_pts && new_pts < d->pts - 99999)) {  // pts can only go up or drop cardinally
36305     if (new_pts < d->pts - 99999) {
36306       LOG(WARNING) << "Pts of " << d->dialog_id << " decreases from " << d->pts << " to " << new_pts << " from "
36307                    << source;
36308     } else {
36309       LOG(INFO) << "Update " << d->dialog_id << " pts to " << new_pts << " from " << source;
36310     }
36311 
36312     d->pts = new_pts;
36313     if (d->pending_read_channel_inbox_pts != 0 && d->pending_read_channel_inbox_pts <= d->pts) {
36314       auto pts = d->pending_read_channel_inbox_pts;
36315       d->pending_read_channel_inbox_pts = 0;
36316       on_dialog_updated(d->dialog_id, "set_channel_pts");
36317       if (d->pts == pts) {
36318         read_history_inbox(d->dialog_id, d->pending_read_channel_inbox_max_message_id,
36319                            d->pending_read_channel_inbox_server_unread_count, "set_channel_pts");
36320       } else if (d->pts > pts) {
36321         repair_channel_server_unread_count(d);
36322       }
36323     }
36324     if (!G()->ignore_background_updates() && have_input_peer(d->dialog_id, AccessRights::Read)) {
36325       G()->td_db()->get_binlog_pmc()->set(get_channel_pts_key(d->dialog_id), to_string(new_pts));
36326     }
36327   } else if (new_pts < d->pts) {
36328     LOG(ERROR) << "Receive wrong pts " << new_pts << " in " << d->dialog_id << " from " << source << ". Current pts is "
36329                << d->pts;
36330   }
36331 }
36332 
need_channel_difference_to_add_message(DialogId dialog_id,const tl_object_ptr<telegram_api::Message> & message_ptr)36333 bool MessagesManager::need_channel_difference_to_add_message(DialogId dialog_id,
36334                                                              const tl_object_ptr<telegram_api::Message> &message_ptr) {
36335   if (dialog_id.get_type() != DialogType::Channel || !have_input_peer(dialog_id, AccessRights::Read) ||
36336       dialog_id == debug_channel_difference_dialog_) {
36337     return false;
36338   }
36339   if (message_ptr == nullptr) {
36340     return true;
36341   }
36342   if (get_message_dialog_id(message_ptr) != dialog_id) {
36343     return false;
36344   }
36345 
36346   Dialog *d = get_dialog_force(dialog_id, "need_channel_difference_to_add_message");
36347   if (d == nullptr) {
36348     return load_channel_pts(dialog_id) > 0 && !is_channel_difference_finished_.count(dialog_id);
36349   }
36350   if (d->last_new_message_id == MessageId()) {
36351     return d->pts > 0 && !d->is_channel_difference_finished;
36352   }
36353 
36354   return get_message_id(message_ptr, false) > d->last_new_message_id;
36355 }
36356 
run_after_channel_difference(DialogId dialog_id,Promise<Unit> && promise)36357 void MessagesManager::run_after_channel_difference(DialogId dialog_id, Promise<Unit> &&promise) {
36358   CHECK(dialog_id.get_type() == DialogType::Channel);
36359   CHECK(have_input_peer(dialog_id, AccessRights::Read));
36360 
36361   run_after_get_channel_difference_[dialog_id].push_back(std::move(promise));
36362 
36363   const Dialog *d = get_dialog(dialog_id);
36364   get_channel_difference(dialog_id, d == nullptr ? load_channel_pts(dialog_id) : d->pts, true,
36365                          "run_after_channel_difference");
36366 }
36367 
running_get_channel_difference(DialogId dialog_id) const36368 bool MessagesManager::running_get_channel_difference(DialogId dialog_id) const {
36369   return active_get_channel_differencies_.count(dialog_id) > 0;
36370 }
36371 
on_channel_get_difference_timeout(DialogId dialog_id)36372 void MessagesManager::on_channel_get_difference_timeout(DialogId dialog_id) {
36373   if (G()->close_flag()) {
36374     return;
36375   }
36376 
36377   CHECK(dialog_id.get_type() == DialogType::Channel);
36378   auto d = get_dialog(dialog_id);
36379   CHECK(d != nullptr);
36380   get_channel_difference(dialog_id, d->pts, true, "on_channel_get_difference_timeout");
36381 }
36382 
36383 class MessagesManager::GetChannelDifferenceLogEvent {
36384  public:
36385   ChannelId channel_id;
36386   int64 access_hash;
36387 
GetChannelDifferenceLogEvent()36388   GetChannelDifferenceLogEvent() : channel_id(), access_hash() {
36389   }
36390 
GetChannelDifferenceLogEvent(ChannelId channel_id,int64 access_hash)36391   GetChannelDifferenceLogEvent(ChannelId channel_id, int64 access_hash)
36392       : channel_id(channel_id), access_hash(access_hash) {
36393   }
36394 
36395   template <class StorerT>
store(StorerT & storer) const36396   void store(StorerT &storer) const {
36397     td::store(channel_id, storer);
36398     td::store(access_hash, storer);
36399   }
36400 
36401   template <class ParserT>
parse(ParserT & parser)36402   void parse(ParserT &parser) {
36403     td::parse(channel_id, parser);
36404     td::parse(access_hash, parser);
36405   }
36406 };
36407 
get_channel_difference(DialogId dialog_id,int32 pts,bool force,const char * source)36408 void MessagesManager::get_channel_difference(DialogId dialog_id, int32 pts, bool force, const char *source) {
36409   if (channel_get_difference_retry_timeout_.has_timeout(dialog_id.get())) {
36410     LOG(INFO) << "Skip running channels.getDifference for " << dialog_id << " from " << source
36411               << " because it is scheduled for later time";
36412     return;
36413   }
36414   LOG_CHECK(dialog_id.get_type() == DialogType::Channel) << dialog_id << " " << source;
36415 
36416   if (active_get_channel_differencies_.count(dialog_id)) {
36417     LOG(INFO) << "Skip running channels.getDifference for " << dialog_id << " from " << source
36418               << " because it has already been run";
36419     return;
36420   }
36421   auto input_channel = td_->contacts_manager_->get_input_channel(dialog_id.get_channel_id());
36422   if (input_channel == nullptr) {
36423     LOG(ERROR) << "Skip running channels.getDifference for " << dialog_id << " from " << source
36424                << " because have no info about the chat";
36425     after_get_channel_difference(dialog_id, false);
36426     return;
36427   }
36428   if (!have_input_peer(dialog_id, AccessRights::Read)) {
36429     LOG(INFO) << "Skip running channels.getDifference for " << dialog_id << " from " << source
36430               << " because have no read access to it";
36431     after_get_channel_difference(dialog_id, false);
36432     return;
36433   }
36434 
36435   if (force && get_channel_difference_to_log_event_id_.count(dialog_id) == 0 && !G()->ignore_background_updates()) {
36436     auto channel_id = dialog_id.get_channel_id();
36437     CHECK(input_channel->get_id() == telegram_api::inputChannel::ID);
36438     auto access_hash = static_cast<const telegram_api::inputChannel &>(*input_channel).access_hash_;
36439     auto log_event = GetChannelDifferenceLogEvent(channel_id, access_hash);
36440     auto log_event_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::GetChannelDifference,
36441                                    get_log_event_storer(log_event));
36442 
36443     get_channel_difference_to_log_event_id_.emplace(dialog_id, log_event_id);
36444   }
36445 
36446   return do_get_channel_difference(dialog_id, pts, force, std::move(input_channel), source);
36447 }
36448 
do_get_channel_difference(DialogId dialog_id,int32 pts,bool force,tl_object_ptr<telegram_api::InputChannel> && input_channel,const char * source)36449 void MessagesManager::do_get_channel_difference(DialogId dialog_id, int32 pts, bool force,
36450                                                 tl_object_ptr<telegram_api::InputChannel> &&input_channel,
36451                                                 const char *source) {
36452   auto inserted = active_get_channel_differencies_.emplace(dialog_id, source);
36453   if (!inserted.second) {
36454     LOG(INFO) << "Skip running channels.getDifference for " << dialog_id << " from " << source
36455               << " because it has already been run";
36456     return;
36457   }
36458   // must work even we know nothing about the dialog
36459 
36460   // can be called multiple times before after_get_channel_difference
36461   const Dialog *d = get_dialog(dialog_id);
36462   if (d != nullptr) {
36463     if (d->message_notification_group.group_id.is_valid()) {
36464       send_closure_later(G()->notification_manager(), &NotificationManager::before_get_chat_difference,
36465                          d->message_notification_group.group_id);
36466     }
36467     if (d->mention_notification_group.group_id.is_valid()) {
36468       send_closure_later(G()->notification_manager(), &NotificationManager::before_get_chat_difference,
36469                          d->mention_notification_group.group_id);
36470     }
36471   }
36472 
36473   int32 limit = td_->auth_manager_->is_bot() ? MAX_BOT_CHANNEL_DIFFERENCE : MAX_CHANNEL_DIFFERENCE;
36474   if (pts <= 0) {
36475     pts = 1;
36476     limit = MIN_CHANNEL_DIFFERENCE;
36477   }
36478 
36479   LOG(INFO) << "-----BEGIN GET CHANNEL DIFFERENCE----- for " << dialog_id << " with pts " << pts << " and limit "
36480             << limit << " from " << source;
36481 
36482   td_->create_handler<GetChannelDifferenceQuery>()->send(dialog_id, std::move(input_channel), pts, limit, force);
36483 }
36484 
process_get_channel_difference_updates(DialogId dialog_id,int32 new_pts,vector<tl_object_ptr<telegram_api::Message>> && new_messages,vector<tl_object_ptr<telegram_api::Update>> && other_updates)36485 void MessagesManager::process_get_channel_difference_updates(
36486     DialogId dialog_id, int32 new_pts, vector<tl_object_ptr<telegram_api::Message>> &&new_messages,
36487     vector<tl_object_ptr<telegram_api::Update>> &&other_updates) {
36488   LOG(INFO) << "In get channel difference for " << dialog_id << " receive " << new_messages.size() << " messages and "
36489             << other_updates.size() << " other updates";
36490   CHECK(!debug_channel_difference_dialog_.is_valid());
36491   debug_channel_difference_dialog_ = dialog_id;
36492 
36493   // identifiers of edited and deleted messages
36494   std::unordered_set<MessageId, MessageIdHash> changed_message_ids;
36495   for (auto &update_ptr : other_updates) {
36496     bool is_good_update = true;
36497     switch (update_ptr->get_id()) {
36498       case telegram_api::updateMessageID::ID: {
36499         // in channels.getDifference updateMessageID can't be received for scheduled messages
36500         auto sent_message_update = move_tl_object_as<telegram_api::updateMessageID>(update_ptr);
36501         on_update_message_id(sent_message_update->random_id_, MessageId(ServerMessageId(sent_message_update->id_)),
36502                              "get_channel_difference");
36503         update_ptr = nullptr;
36504         break;
36505       }
36506       case telegram_api::updateDeleteChannelMessages::ID: {
36507         auto *update = static_cast<const telegram_api::updateDeleteChannelMessages *>(update_ptr.get());
36508         if (DialogId(ChannelId(update->channel_id_)) != dialog_id) {
36509           is_good_update = false;
36510         } else {
36511           for (auto &message : update->messages_) {
36512             changed_message_ids.insert(MessageId(ServerMessageId(message)));
36513           }
36514         }
36515         break;
36516       }
36517       case telegram_api::updateEditChannelMessage::ID: {
36518         auto *update = static_cast<const telegram_api::updateEditChannelMessage *>(update_ptr.get());
36519         auto full_message_id = get_full_message_id(update->message_, false);
36520         if (full_message_id.get_dialog_id() != dialog_id) {
36521           is_good_update = false;
36522         } else {
36523           changed_message_ids.insert(full_message_id.get_message_id());
36524         }
36525         break;
36526       }
36527       case telegram_api::updatePinnedChannelMessages::ID: {
36528         auto *update = static_cast<const telegram_api::updatePinnedChannelMessages *>(update_ptr.get());
36529         if (DialogId(ChannelId(update->channel_id_)) != dialog_id) {
36530           is_good_update = false;
36531         }
36532         break;
36533       }
36534       default:
36535         is_good_update = false;
36536         break;
36537     }
36538     if (!is_good_update) {
36539       LOG(ERROR) << "Receive wrong update in channelDifference of " << dialog_id << ": " << to_string(update_ptr);
36540       update_ptr = nullptr;
36541     }
36542   }
36543 
36544   auto is_edited_message = [](const tl_object_ptr<telegram_api::Message> &message) {
36545     if (message->get_id() != telegram_api::message::ID) {
36546       return false;
36547     }
36548     return static_cast<const telegram_api::message *>(message.get())->edit_date_ > 0;
36549   };
36550 
36551   for (auto &message : new_messages) {
36552     if (is_edited_message(message)) {
36553       changed_message_ids.insert(get_message_id(message, false));
36554     }
36555   }
36556 
36557   // extract awaited sent messages, which were edited or deleted after that
36558   auto postponed_updates_it = postponed_channel_updates_.find(dialog_id);
36559   struct AwaitedMessage {
36560     tl_object_ptr<telegram_api::Message> message;
36561     Promise<Unit> promise;
36562   };
36563   std::map<MessageId, AwaitedMessage> awaited_messages;
36564   if (postponed_updates_it != postponed_channel_updates_.end()) {
36565     auto &updates = postponed_updates_it->second;
36566     while (!updates.empty()) {
36567       auto it = updates.begin();
36568       auto update_pts = it->second.pts;
36569       if (update_pts > new_pts) {
36570         break;
36571       }
36572 
36573       auto update = std::move(it->second.update);
36574       auto promise = std::move(it->second.promise);
36575       updates.erase(it);
36576 
36577       if (update->get_id() == telegram_api::updateNewChannelMessage::ID) {
36578         auto update_new_channel_message = static_cast<telegram_api::updateNewChannelMessage *>(update.get());
36579         auto message_id = get_message_id(update_new_channel_message->message_, false);
36580         FullMessageId full_message_id(dialog_id, message_id);
36581         if (update_message_ids_.find(full_message_id) != update_message_ids_.end() &&
36582             changed_message_ids.find(message_id) != changed_message_ids.end()) {
36583           changed_message_ids.erase(message_id);
36584           AwaitedMessage awaited_message;
36585           awaited_message.message = std::move(update_new_channel_message->message_);
36586           awaited_message.promise = std::move(promise);
36587           awaited_messages.emplace(message_id, std::move(awaited_message));
36588           continue;
36589         }
36590       }
36591 
36592       LOG(INFO) << "Skip to be applied from getChannelDifference " << to_string(update);
36593       promise.set_value(Unit());
36594     }
36595     if (updates.empty()) {
36596       postponed_channel_updates_.erase(postponed_updates_it);
36597     }
36598   }
36599 
36600   // if last message is pretty old, we might have missed the update
36601   bool need_repair_unread_count =
36602       !new_messages.empty() && get_message_date(new_messages[0]) < G()->unix_time() - 2 * 86400;
36603 
36604   auto it = awaited_messages.begin();
36605   for (auto &message : new_messages) {
36606     auto message_id = get_message_id(message, false);
36607     while (it != awaited_messages.end() && it->first < message_id) {
36608       on_get_message(std::move(it->second.message), true, true, false, true, true, "postponed channel update");
36609       it->second.promise.set_value(Unit());
36610       ++it;
36611     }
36612     Promise<Unit> promise;
36613     if (it != awaited_messages.end() && it->first == message_id) {
36614       if (is_edited_message(message)) {
36615         // the new message is edited, apply postponed one and move this to updateEditChannelMessage
36616         other_updates.push_back(make_tl_object<telegram_api::updateEditChannelMessage>(std::move(message), new_pts, 0));
36617         message = std::move(it->second.message);
36618         promise = std::move(it->second.promise);
36619       } else {
36620         it->second.promise.set_value(Unit());
36621       }
36622       ++it;
36623     }
36624     on_get_message(std::move(message), true, true, false, true, true, "get channel difference");
36625     promise.set_value(Unit());
36626   }
36627   while (it != awaited_messages.end()) {
36628     on_get_message(std::move(it->second.message), true, true, false, true, true, "postponed channel update 2");
36629     it->second.promise.set_value(Unit());
36630     ++it;
36631   }
36632 
36633   for (auto &update : other_updates) {
36634     if (update != nullptr) {
36635       process_channel_update(std::move(update));
36636     }
36637   }
36638   LOG_CHECK(!running_get_channel_difference(dialog_id)) << '"' << active_get_channel_differencies_[dialog_id] << '"';
36639 
36640   if (need_repair_unread_count) {
36641     repair_channel_server_unread_count(get_dialog(dialog_id));
36642   }
36643 
36644   CHECK(debug_channel_difference_dialog_ == dialog_id);
36645   debug_channel_difference_dialog_ = DialogId();
36646 }
36647 
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<tl_object_ptr<telegram_api::Message>> && messages)36648 void MessagesManager::on_get_channel_dialog(DialogId dialog_id, MessageId last_message_id,
36649                                             MessageId read_inbox_max_message_id, int32 server_unread_count,
36650                                             int32 unread_mention_count, MessageId read_outbox_max_message_id,
36651                                             vector<tl_object_ptr<telegram_api::Message>> &&messages) {
36652   std::unordered_map<FullMessageId, tl_object_ptr<telegram_api::Message>, FullMessageIdHash> full_message_id_to_message;
36653   for (auto &message : messages) {
36654     auto message_id = get_message_id(message, false);
36655     auto message_dialog_id = get_message_dialog_id(message);
36656     if (!message_dialog_id.is_valid()) {
36657       message_dialog_id = dialog_id;
36658     }
36659     auto full_message_id = FullMessageId(message_dialog_id, message_id);
36660     full_message_id_to_message[full_message_id] = std::move(message);
36661   }
36662 
36663   FullMessageId last_full_message_id(dialog_id, last_message_id);
36664   if (last_message_id.is_valid()) {
36665     if (full_message_id_to_message.count(last_full_message_id) == 0) {
36666       LOG(ERROR) << "Last " << last_message_id << " in " << dialog_id << " not found. Have:";
36667       for (auto &message : full_message_id_to_message) {
36668         LOG(ERROR) << to_string(message.second);
36669       }
36670       return;
36671     }
36672   }
36673   CHECK(!last_message_id.is_scheduled());
36674 
36675   Dialog *d = get_dialog(dialog_id);
36676   CHECK(d != nullptr);
36677 
36678   // TODO gaps support
36679   // There are many ways of handling a gap in a channel:
36680   // 1) Delete all known messages in the chat, begin from scratch. It is easy to implement, but suddenly disappearing
36681   //    messages looks awful for the user.
36682   // 2) Save all messages loaded in the memory until application restart, but delete all messages from the database.
36683   //    Messages left in the memory must be lazily updated using calls to getHistory. It looks much smoothly for the
36684   //    user, he will need to redownload messages only after client restart. Unsynchronized messages left in the
36685   //    memory shouldn't be saved to database, results of getHistory and getMessage must be used to update state of
36686   //    deleted and edited messages left in the memory.
36687   // 3) Save all messages loaded in the memory and stored in the database without saving that some messages form
36688   //    continuous ranges. Messages in the database will be excluded from results of getChatHistory and
36689   //    searchChatMessages after application restart and will be available only through getMessage.
36690   //    Every message should still be checked using getHistory. It has more disadvantages over 2) than advantages.
36691   // 4) Save all messages with saving all data about continuous message ranges. Messages from the database may be used
36692   //    as results of getChatHistory and (if implemented continuous ranges support for searching shared media)
36693   //    searchChatMessages. The messages should still be lazily checked using getHistory, but they are still available
36694   //    offline. It is the best way for gaps support, but it is pretty hard to implement correctly.
36695   // It should be also noted that some messages like outgoing live location messages shouldn't be deleted.
36696 
36697   if (last_message_id > d->last_new_message_id) {
36698     // TODO properly support last_message_id <= d->last_new_message_id
36699     set_dialog_first_database_message_id(d, MessageId(), "on_get_channel_dialog 6");
36700     set_dialog_last_database_message_id(d, MessageId(), "on_get_channel_dialog 7");
36701     d->have_full_history = false;
36702     d->is_empty = false;
36703   }
36704   invalidate_message_indexes(d);
36705 
36706   on_dialog_updated(dialog_id, "on_get_channel_dialog 10");
36707 
36708   // TODO properly support last_message_id <= d->last_new_message_id
36709   if (last_message_id > d->last_new_message_id) {  // if last message is really a new message
36710     if (!d->last_new_message_id.is_valid() && last_message_id <= d->max_added_message_id) {
36711       auto prev_message_id = MessageId(ServerMessageId(last_message_id.get_server_message_id().get() - 1));
36712       remove_dialog_newer_messages(d, prev_message_id, "on_get_channel_dialog 15");
36713     }
36714     d->last_new_message_id = MessageId();
36715     set_dialog_last_message_id(d, MessageId(), "on_get_channel_dialog 20");
36716     send_update_chat_last_message(d, "on_get_channel_dialog 30");
36717     auto added_full_message_id = on_get_message(std::move(full_message_id_to_message[last_full_message_id]), true, true,
36718                                                 false, true, true, "channel difference too long");
36719     if (added_full_message_id.get_message_id().is_valid()) {
36720       if (added_full_message_id.get_message_id() == d->last_new_message_id) {
36721         CHECK(last_full_message_id == added_full_message_id);
36722         CHECK(d->last_message_id == d->last_new_message_id);
36723       } else {
36724         LOG(ERROR) << added_full_message_id << " doesn't became last new message, which is " << d->last_new_message_id;
36725         dump_debug_message_op(d, 2);
36726       }
36727     } else if (last_message_id > d->last_new_message_id) {
36728       set_dialog_last_new_message_id(d, last_message_id,
36729                                      "on_get_channel_dialog 40");  // skip updates about some messages
36730     }
36731   }
36732 
36733   if (d->last_read_inbox_message_id.is_valid() && !d->last_read_inbox_message_id.is_server() &&
36734       read_inbox_max_message_id == d->last_read_inbox_message_id.get_prev_server_message_id()) {
36735     read_inbox_max_message_id = d->last_read_inbox_message_id;
36736   }
36737   if (d->server_unread_count != server_unread_count || d->last_read_inbox_message_id != read_inbox_max_message_id) {
36738     set_dialog_last_read_inbox_message_id(d, read_inbox_max_message_id, server_unread_count, d->local_unread_count,
36739                                           false, "on_get_channel_dialog 50");
36740   }
36741   if (d->unread_mention_count != unread_mention_count) {
36742     set_dialog_unread_mention_count(d, unread_mention_count);
36743     update_dialog_mention_notification_count(d);
36744     send_update_chat_unread_mention_count(d);
36745   }
36746 
36747   if (d->last_read_outbox_message_id != read_outbox_max_message_id) {
36748     set_dialog_last_read_outbox_message_id(d, read_outbox_max_message_id);
36749   }
36750 }
36751 
on_get_channel_difference(DialogId dialog_id,int32 request_pts,int32 request_limit,tl_object_ptr<telegram_api::updates_ChannelDifference> && difference_ptr)36752 void MessagesManager::on_get_channel_difference(
36753     DialogId dialog_id, int32 request_pts, int32 request_limit,
36754     tl_object_ptr<telegram_api::updates_ChannelDifference> &&difference_ptr) {
36755   LOG(INFO) << "----- END  GET CHANNEL DIFFERENCE----- for " << dialog_id;
36756   CHECK(active_get_channel_differencies_.count(dialog_id) == 1);
36757   active_get_channel_differencies_.erase(dialog_id);
36758   auto d = get_dialog_force(dialog_id, "on_get_channel_difference");
36759 
36760   if (difference_ptr == nullptr) {
36761     bool have_access = have_input_peer(dialog_id, AccessRights::Read);
36762     if (have_access) {
36763       if (d == nullptr) {
36764         force_create_dialog(dialog_id, "on_get_channel_difference failed");
36765       }
36766       auto &delay = channel_get_difference_retry_timeouts_[dialog_id];
36767       if (delay == 0) {
36768         delay = 1;
36769       }
36770       channel_get_difference_retry_timeout_.add_timeout_in(dialog_id.get(), delay);
36771       delay *= 2;
36772       if (delay > 60) {
36773         delay = Random::fast(60, 80);
36774       }
36775     } else {
36776       after_get_channel_difference(dialog_id, false);
36777     }
36778     return;
36779   }
36780 
36781   channel_get_difference_retry_timeouts_.erase(dialog_id);
36782 
36783   LOG(INFO) << "Receive result of getChannelDifference for " << dialog_id << " with pts = " << request_pts
36784             << " and limit = " << request_limit << ": " << to_string(difference_ptr);
36785 
36786   bool have_new_messages = false;
36787   switch (difference_ptr->get_id()) {
36788     case telegram_api::updates_channelDifferenceEmpty::ID:
36789       if (d == nullptr) {
36790         // no need to create the dialog
36791         after_get_channel_difference(dialog_id, true);
36792         return;
36793       }
36794       break;
36795     case telegram_api::updates_channelDifference::ID: {
36796       auto difference = static_cast<telegram_api::updates_channelDifference *>(difference_ptr.get());
36797       have_new_messages = !difference->new_messages_.empty();
36798       td_->contacts_manager_->on_get_users(std::move(difference->users_), "updates.channelDifference");
36799       td_->contacts_manager_->on_get_chats(std::move(difference->chats_), "updates.channelDifference");
36800       break;
36801     }
36802     case telegram_api::updates_channelDifferenceTooLong::ID: {
36803       auto difference = static_cast<telegram_api::updates_channelDifferenceTooLong *>(difference_ptr.get());
36804       have_new_messages = difference->dialog_->get_id() == telegram_api::dialog::ID && !difference->messages_.empty();
36805       td_->contacts_manager_->on_get_users(std::move(difference->users_), "updates.channelDifferenceTooLong");
36806       td_->contacts_manager_->on_get_chats(std::move(difference->chats_), "updates.channelDifferenceTooLong");
36807       break;
36808     }
36809     default:
36810       UNREACHABLE();
36811   }
36812 
36813   bool need_update_dialog_pos = false;
36814   if (d == nullptr) {
36815     if (have_new_messages) {
36816       CHECK(!being_added_by_new_message_dialog_id_.is_valid());
36817       being_added_by_new_message_dialog_id_ = dialog_id;
36818     }
36819     d = add_dialog(dialog_id, "on_get_channel_difference");
36820     being_added_by_new_message_dialog_id_ = DialogId();
36821     need_update_dialog_pos = true;
36822   }
36823 
36824   int32 cur_pts = d->pts <= 0 ? 1 : d->pts;
36825   LOG_IF(ERROR, cur_pts != request_pts) << "Channel pts has changed from " << request_pts << " to " << d->pts << " in "
36826                                         << dialog_id << " during getChannelDifference";
36827 
36828   bool is_final = true;
36829   int32 timeout = 0;
36830   switch (difference_ptr->get_id()) {
36831     case telegram_api::updates_channelDifferenceEmpty::ID: {
36832       auto difference = move_tl_object_as<telegram_api::updates_channelDifferenceEmpty>(difference_ptr);
36833       int32 flags = difference->flags_;
36834       is_final = (flags & CHANNEL_DIFFERENCE_FLAG_IS_FINAL) != 0;
36835       LOG_IF(ERROR, !is_final) << "Receive channelDifferenceEmpty as result of getChannelDifference with pts = "
36836                                << request_pts << " and limit = " << request_limit << " in " << dialog_id
36837                                << ", but it is not final";
36838       if (flags & CHANNEL_DIFFERENCE_FLAG_HAS_TIMEOUT) {
36839         timeout = difference->timeout_;
36840       }
36841 
36842       // bots can receive channelDifferenceEmpty with pts bigger than known pts
36843       LOG_IF(ERROR, request_pts != difference->pts_ && !td_->auth_manager_->is_bot())
36844           << "Receive channelDifferenceEmpty as result of getChannelDifference with pts = " << request_pts
36845           << " and limit = " << request_limit << " in " << dialog_id << ", but pts has changed from " << request_pts
36846           << " to " << difference->pts_;
36847       set_channel_pts(d, difference->pts_, "channel difference empty");
36848       break;
36849     }
36850     case telegram_api::updates_channelDifference::ID: {
36851       auto difference = move_tl_object_as<telegram_api::updates_channelDifference>(difference_ptr);
36852 
36853       int32 flags = difference->flags_;
36854       is_final = (flags & CHANNEL_DIFFERENCE_FLAG_IS_FINAL) != 0;
36855       if (flags & CHANNEL_DIFFERENCE_FLAG_HAS_TIMEOUT) {
36856         timeout = difference->timeout_;
36857       }
36858 
36859       auto new_pts = difference->pts_;
36860       if (request_pts >= new_pts && request_pts > 1 && (request_pts > new_pts || !td_->auth_manager_->is_bot())) {
36861         LOG(ERROR) << "Receive channelDifference as result of getChannelDifference with pts = " << request_pts
36862                    << " and limit = " << request_limit << " in " << dialog_id << ", but pts has changed from " << d->pts
36863                    << " to " << new_pts << ". Difference: " << oneline(to_string(difference));
36864         new_pts = request_pts + 1;
36865       }
36866 
36867       if (difference->new_messages_.size() > 1) {
36868         // check that new messages are received in increasing message_id order
36869         MessageId cur_message_id;
36870         for (const auto &message : difference->new_messages_) {
36871           auto message_id = get_message_id(message, false);
36872           if (message_id <= cur_message_id) {
36873             // TODO move to ERROR
36874             LOG(FATAL) << "Receive " << cur_message_id << " after " << message_id << " in channelDifference of "
36875                        << dialog_id << " with pts " << request_pts << " and limit " << request_limit << ": "
36876                        << to_string(difference);
36877             after_get_channel_difference(dialog_id, false);
36878             return;
36879           }
36880           cur_message_id = message_id;
36881         }
36882       }
36883 
36884       process_get_channel_difference_updates(dialog_id, new_pts, std::move(difference->new_messages_),
36885                                              std::move(difference->other_updates_));
36886 
36887       set_channel_pts(d, new_pts, "channel difference");
36888       break;
36889     }
36890     case telegram_api::updates_channelDifferenceTooLong::ID: {
36891       auto difference = move_tl_object_as<telegram_api::updates_channelDifferenceTooLong>(difference_ptr);
36892 
36893       tl_object_ptr<telegram_api::dialog> dialog;
36894       switch (difference->dialog_->get_id()) {
36895         case telegram_api::dialog::ID:
36896           dialog = telegram_api::move_object_as<telegram_api::dialog>(difference->dialog_);
36897           break;
36898         case telegram_api::dialogFolder::ID:
36899           return after_get_channel_difference(dialog_id, false);
36900         default:
36901           UNREACHABLE();
36902           return;
36903       }
36904 
36905       CHECK(dialog != nullptr);
36906       if ((dialog->flags_ & telegram_api::dialog::PTS_MASK) == 0) {
36907         LOG(ERROR) << "Receive " << dialog_id << " without pts";
36908         return after_get_channel_difference(dialog_id, false);
36909       }
36910 
36911       int32 flags = difference->flags_;
36912       is_final = (flags & CHANNEL_DIFFERENCE_FLAG_IS_FINAL) != 0;
36913       if (flags & CHANNEL_DIFFERENCE_FLAG_HAS_TIMEOUT) {
36914         timeout = difference->timeout_;
36915       }
36916 
36917       auto new_pts = dialog->pts_;
36918       if (request_pts > new_pts - request_limit) {
36919         LOG(ERROR) << "Receive channelDifferenceTooLong as result of getChannelDifference with pts = " << request_pts
36920                    << " and limit = " << request_limit << " in " << dialog_id << ", but pts has changed from " << d->pts
36921                    << " to " << new_pts << ". Difference: " << oneline(to_string(difference));
36922         if (request_pts >= new_pts) {
36923           new_pts = request_pts + 1;
36924         }
36925       }
36926 
36927       set_dialog_folder_id(d, FolderId((dialog->flags_ & DIALOG_FLAG_HAS_FOLDER_ID) != 0 ? dialog->folder_id_ : 0));
36928 
36929       on_update_dialog_notify_settings(dialog_id, std::move(dialog->notify_settings_),
36930                                        "updates.channelDifferenceTooLong");
36931 
36932       bool is_marked_as_unread = dialog->unread_mark_;
36933       if (is_marked_as_unread != d->is_marked_as_unread) {
36934         set_dialog_is_marked_as_unread(d, is_marked_as_unread);
36935       }
36936 
36937       update_dialog_draft_message(d, get_draft_message(td_->contacts_manager_.get(), std::move(dialog->draft_)), true,
36938                                   false);
36939 
36940       on_get_channel_dialog(dialog_id, MessageId(ServerMessageId(dialog->top_message_)),
36941                             MessageId(ServerMessageId(dialog->read_inbox_max_id_)), dialog->unread_count_,
36942                             dialog->unread_mentions_count_, MessageId(ServerMessageId(dialog->read_outbox_max_id_)),
36943                             std::move(difference->messages_));
36944       update_dialog_pos(d, "updates.channelDifferenceTooLong");
36945 
36946       if (!td_->auth_manager_->is_bot()) {
36947         // set is_pinned only after updating dialog pos to ensure that order is initialized
36948         bool is_pinned = (dialog->flags_ & DIALOG_FLAG_IS_PINNED) != 0;
36949         bool was_pinned = is_dialog_pinned(DialogListId(d->folder_id), dialog_id);
36950         if (is_pinned != was_pinned) {
36951           set_dialog_is_pinned(DialogListId(d->folder_id), d, is_pinned);
36952         }
36953       }
36954 
36955       set_channel_pts(d, new_pts, "channel difference too long");
36956       break;
36957     }
36958     default:
36959       UNREACHABLE();
36960   }
36961 
36962   if (need_update_dialog_pos) {
36963     update_dialog_pos(d, "on_get_channel_difference");
36964   }
36965 
36966   if (!is_final) {
36967     LOG_IF(ERROR, timeout > 0) << "Have timeout in nonfinal ChannelDifference in " << dialog_id;
36968     get_channel_difference(dialog_id, d->pts, true, "on_get_channel_difference");
36969     return;
36970   }
36971 
36972   LOG_IF(ERROR, timeout == 0) << "Have no timeout in final ChannelDifference in " << dialog_id;
36973   if (timeout > 0 && d->is_opened) {
36974     channel_get_difference_timeout_.add_timeout_in(dialog_id.get(), timeout);
36975   }
36976   after_get_channel_difference(dialog_id, true);
36977 }
36978 
after_get_channel_difference(DialogId dialog_id,bool success)36979 void MessagesManager::after_get_channel_difference(DialogId dialog_id, bool success) {
36980   LOG(INFO) << "After " << (success ? "" : "un") << "successful get channel difference in " << dialog_id;
36981   LOG_CHECK(!running_get_channel_difference(dialog_id)) << '"' << active_get_channel_differencies_[dialog_id] << '"';
36982 
36983   auto log_event_it = get_channel_difference_to_log_event_id_.find(dialog_id);
36984   if (log_event_it != get_channel_difference_to_log_event_id_.end()) {
36985     if (!G()->close_flag()) {
36986       binlog_erase(G()->td_db()->get_binlog(), log_event_it->second);
36987     }
36988     get_channel_difference_to_log_event_id_.erase(log_event_it);
36989   }
36990 
36991   auto d = get_dialog(dialog_id);
36992   bool have_access = have_input_peer(dialog_id, AccessRights::Read);
36993   auto pts = d != nullptr ? d->pts : load_channel_pts(dialog_id);
36994   auto postponed_updates_it = postponed_channel_updates_.find(dialog_id);
36995   if (postponed_updates_it != postponed_channel_updates_.end()) {
36996     auto &updates = postponed_updates_it->second;
36997     LOG(INFO) << "Begin to apply " << updates.size() << " postponed channel updates";
36998     while (!updates.empty()) {
36999       auto it = updates.begin();
37000       auto update = std::move(it->second.update);
37001       auto update_pts = it->second.pts;
37002       auto update_pts_count = it->second.pts_count;
37003       auto promise = std::move(it->second.promise);
37004       updates.erase(it);
37005 
37006       auto old_size = updates.size();
37007       auto update_id = update->get_id();
37008       if (have_access) {
37009         add_pending_channel_update(dialog_id, std::move(update), update_pts, update_pts_count, std::move(promise),
37010                                    "apply postponed channel updates", true);
37011       } else {
37012         promise.set_value(Unit());
37013       }
37014       if (updates.size() != old_size || running_get_channel_difference(dialog_id)) {
37015         if (success && update_pts - 10000 < pts && update_pts_count == 1) {
37016           // if getChannelDifference was successful and update pts is near channel pts,
37017           // we hope that the update eventually can be applied
37018           LOG(INFO) << "Can't apply postponed channel updates";
37019         } else {
37020           // otherwise protect from getChannelDifference repeating calls by dropping postponed updates
37021           LOG(WARNING) << "Failed to apply postponed updates of type " << update_id << " in " << dialog_id
37022                        << " with pts " << pts << ", update pts is " << update_pts << ", update pts count is "
37023                        << update_pts_count;
37024           vector<Promise<Unit>> update_promises;
37025           for (auto &postponed_update : updates) {
37026             update_promises.push_back(std::move(postponed_update.second.promise));
37027           }
37028           updates.clear();
37029           for (auto &update_promise : update_promises) {
37030             update_promise.set_value(Unit());
37031           }
37032         }
37033         break;
37034       }
37035     }
37036     if (updates.empty()) {
37037       postponed_channel_updates_.erase(postponed_updates_it);
37038     }
37039     LOG(INFO) << "Finish to apply postponed channel updates";
37040   }
37041 
37042   if (d != nullptr) {
37043     d->is_channel_difference_finished = true;
37044 
37045     if (d->message_notification_group.group_id.is_valid()) {
37046       send_closure_later(G()->notification_manager(), &NotificationManager::after_get_chat_difference,
37047                          d->message_notification_group.group_id);
37048     }
37049     if (d->mention_notification_group.group_id.is_valid()) {
37050       send_closure_later(G()->notification_manager(), &NotificationManager::after_get_chat_difference,
37051                          d->mention_notification_group.group_id);
37052     }
37053   } else {
37054     is_channel_difference_finished_.insert(dialog_id);
37055   }
37056 
37057   if (postponed_chat_read_inbox_updates_.erase(dialog_id) > 0) {
37058     send_update_chat_read_inbox(d, true, "after_get_channel_difference");
37059   }
37060 
37061   auto promise_it = run_after_get_channel_difference_.find(dialog_id);
37062   if (promise_it != run_after_get_channel_difference_.end()) {
37063     vector<Promise<Unit>> promises = std::move(promise_it->second);
37064     run_after_get_channel_difference_.erase(promise_it);
37065 
37066     for (auto &promise : promises) {
37067       promise.set_value(Unit());
37068     }
37069   }
37070 
37071   auto it = pending_channel_on_get_dialogs_.find(dialog_id);
37072   if (it != pending_channel_on_get_dialogs_.end()) {
37073     LOG(INFO) << "Apply postponed results of channel getDialogs for " << dialog_id;
37074     PendingOnGetDialogs res = std::move(it->second);
37075     pending_channel_on_get_dialogs_.erase(it);
37076 
37077     on_get_dialogs(res.folder_id, std::move(res.dialogs), res.total_count, std::move(res.messages),
37078                    std::move(res.promise));
37079   }
37080 
37081   if (d != nullptr && !td_->auth_manager_->is_bot() && have_access && !d->last_message_id.is_valid() && !d->is_empty &&
37082       (d->order != DEFAULT_ORDER || is_dialog_sponsored(d))) {
37083     get_history_from_the_end_impl(d, true, false, Auto());
37084   }
37085 }
37086 
reget_message_from_server_if_needed(DialogId dialog_id,const Message * m)37087 void MessagesManager::reget_message_from_server_if_needed(DialogId dialog_id, const Message *m) {
37088   if (!m->message_id.is_any_server() || dialog_id.get_type() == DialogType::SecretChat) {
37089     return;
37090   }
37091 
37092   if (need_reget_message_content(m->content.get()) || (m->legacy_layer != 0 && m->legacy_layer < MTPROTO_LAYER)) {
37093     FullMessageId full_message_id{dialog_id, m->message_id};
37094     LOG(INFO) << "Reget from server " << full_message_id;
37095     get_message_from_server(full_message_id, Auto(), "reget_message_from_server_if_needed");
37096   }
37097 }
37098 
speculatively_update_active_group_call_id(Dialog * d,const Message * m)37099 void MessagesManager::speculatively_update_active_group_call_id(Dialog *d, const Message *m) {
37100   CHECK(m != nullptr);
37101   if (!m->message_id.is_any_server() || m->content->get_type() != MessageContentType::GroupCall) {
37102     return;
37103   }
37104 
37105   InputGroupCallId input_group_call_id;
37106   bool is_ended;
37107   std::tie(input_group_call_id, is_ended) = get_message_content_group_call_info(m->content.get());
37108   d->has_expected_active_group_call_id = true;
37109   if (is_ended) {
37110     d->expected_active_group_call_id = InputGroupCallId();
37111     if (d->active_group_call_id == input_group_call_id) {
37112       on_update_dialog_group_call_id(d->dialog_id, InputGroupCallId());
37113     }
37114   } else {
37115     d->expected_active_group_call_id = input_group_call_id;
37116     if (d->active_group_call_id != input_group_call_id && !td_->auth_manager_->is_bot()) {
37117       repair_dialog_active_group_call_id(d->dialog_id);
37118     }
37119   }
37120 }
37121 
speculatively_update_channel_participants(DialogId dialog_id,const Message * m)37122 void MessagesManager::speculatively_update_channel_participants(DialogId dialog_id, const Message *m) {
37123   CHECK(m != nullptr);
37124   if (!m->message_id.is_any_server() || dialog_id.get_type() != DialogType::Channel || !m->sender_user_id.is_valid()) {
37125     return;
37126   }
37127 
37128   auto channel_id = dialog_id.get_channel_id();
37129   UserId my_user_id(td_->contacts_manager_->get_my_id());
37130   bool by_me = m->sender_user_id == my_user_id;
37131   switch (m->content->get_type()) {
37132     case MessageContentType::ChatAddUsers:
37133       send_closure_later(G()->contacts_manager(), &ContactsManager::speculative_add_channel_participants, channel_id,
37134                          get_message_content_added_user_ids(m->content.get()), m->sender_user_id, m->date, by_me);
37135       break;
37136     case MessageContentType::ChatJoinedByLink:
37137       send_closure_later(G()->contacts_manager(), &ContactsManager::speculative_add_channel_participants, channel_id,
37138                          vector<UserId>{m->sender_user_id}, m->sender_user_id, m->date, by_me);
37139       break;
37140     case MessageContentType::ChatDeleteUser:
37141       send_closure_later(G()->contacts_manager(), &ContactsManager::speculative_delete_channel_participant, channel_id,
37142                          get_message_content_deleted_user_id(m->content.get()), by_me);
37143       break;
37144     default:
37145       break;
37146   }
37147 }
37148 
update_sent_message_contents(DialogId dialog_id,const Message * m)37149 void MessagesManager::update_sent_message_contents(DialogId dialog_id, const Message *m) {
37150   CHECK(m != nullptr);
37151   if (td_->auth_manager_->is_bot() || (!m->is_outgoing && dialog_id != get_my_dialog_id()) ||
37152       dialog_id.get_type() == DialogType::SecretChat || m->message_id.is_local() || m->forward_info != nullptr ||
37153       m->had_forward_info) {
37154     return;
37155   }
37156 
37157   on_sent_message_content(td_, m->content.get());
37158 }
37159 
update_used_hashtags(DialogId dialog_id,const Message * m)37160 void MessagesManager::update_used_hashtags(DialogId dialog_id, const Message *m) {
37161   CHECK(m != nullptr);
37162   if (td_->auth_manager_->is_bot() || (!m->is_outgoing && dialog_id != get_my_dialog_id()) ||
37163       m->via_bot_user_id.is_valid() || m->hide_via_bot || m->forward_info != nullptr || m->had_forward_info) {
37164     return;
37165   }
37166 
37167   ::td::update_used_hashtags(td_, m->content.get());
37168 }
37169 
update_top_dialogs(DialogId dialog_id,const Message * m)37170 void MessagesManager::update_top_dialogs(DialogId dialog_id, const Message *m) {
37171   CHECK(m != nullptr);
37172   auto dialog_type = dialog_id.get_type();
37173   if (td_->auth_manager_->is_bot() || (!m->is_outgoing && dialog_id != get_my_dialog_id()) ||
37174       dialog_type == DialogType::SecretChat || !m->message_id.is_any_server()) {
37175     return;
37176   }
37177 
37178   bool is_forward = m->forward_info != nullptr || m->had_forward_info;
37179   if (m->via_bot_user_id.is_valid() && !is_forward) {
37180     // forwarded game messages can't be distinguished from sent via bot game messages, so increase rating anyway
37181     on_dialog_used(TopDialogCategory::BotInline, DialogId(m->via_bot_user_id), m->date);
37182   }
37183 
37184   if (is_forward) {
37185     auto &last_forward_date = last_outgoing_forwarded_message_date_[dialog_id];
37186     if (last_forward_date < m->date) {
37187       TopDialogCategory category =
37188           dialog_type == DialogType::User ? TopDialogCategory::ForwardUsers : TopDialogCategory::ForwardChats;
37189       on_dialog_used(category, dialog_id, m->date);
37190       last_forward_date = m->date;
37191     }
37192   }
37193 
37194   TopDialogCategory category = TopDialogCategory::Size;
37195   switch (dialog_type) {
37196     case DialogType::User: {
37197       if (td_->contacts_manager_->is_user_bot(dialog_id.get_user_id())) {
37198         category = TopDialogCategory::BotPM;
37199       } else {
37200         category = TopDialogCategory::Correspondent;
37201       }
37202       break;
37203     }
37204     case DialogType::Chat:
37205       category = TopDialogCategory::Group;
37206       break;
37207     case DialogType::Channel:
37208       switch (td_->contacts_manager_->get_channel_type(dialog_id.get_channel_id())) {
37209         case ContactsManager::ChannelType::Broadcast:
37210           category = TopDialogCategory::Channel;
37211           break;
37212         case ContactsManager::ChannelType::Megagroup:
37213           category = TopDialogCategory::Group;
37214           break;
37215         case ContactsManager::ChannelType::Unknown:
37216           break;
37217         default:
37218           UNREACHABLE();
37219           break;
37220       }
37221       break;
37222     case DialogType::SecretChat:
37223     case DialogType::None:
37224     default:
37225       UNREACHABLE();
37226   }
37227   if (category != TopDialogCategory::Size) {
37228     on_dialog_used(category, dialog_id, m->date);
37229   }
37230 }
37231 
update_forward_count(DialogId dialog_id,const Message * m)37232 void MessagesManager::update_forward_count(DialogId dialog_id, const Message *m) {
37233   if (!td_->auth_manager_->is_bot() && m->forward_info != nullptr && m->forward_info->sender_dialog_id.is_valid() &&
37234       m->forward_info->message_id.is_valid() &&
37235       (!is_discussion_message(dialog_id, m) || m->forward_info->sender_dialog_id != m->forward_info->from_dialog_id ||
37236        m->forward_info->message_id != m->forward_info->from_message_id)) {
37237     update_forward_count(m->forward_info->sender_dialog_id, m->forward_info->message_id, m->date);
37238   }
37239 }
37240 
update_forward_count(DialogId dialog_id,MessageId message_id,int32 update_date)37241 void MessagesManager::update_forward_count(DialogId dialog_id, MessageId message_id, int32 update_date) {
37242   CHECK(!td_->auth_manager_->is_bot());
37243   Dialog *d = get_dialog(dialog_id);
37244   CHECK(d != nullptr);
37245   Message *m = get_message_force(d, message_id, "update_forward_count");
37246   if (m != nullptr && !m->message_id.is_scheduled() && m->message_id.is_server() && m->view_count > 0 &&
37247       m->interaction_info_update_date < update_date) {
37248     if (m->forward_count == 0) {
37249       m->forward_count++;
37250       send_update_message_interaction_info(dialog_id, m);
37251       on_message_changed(d, m, true, "update_forward_count");
37252     }
37253 
37254     if (d->pending_viewed_message_ids.insert(m->message_id).second) {
37255       pending_message_views_timeout_.add_timeout_in(dialog_id.get(), 0.0);
37256     }
37257   }
37258 }
37259 
update_has_outgoing_messages(DialogId dialog_id,const Message * m)37260 void MessagesManager::update_has_outgoing_messages(DialogId dialog_id, const Message *m) {
37261   CHECK(m != nullptr);
37262   if (td_->auth_manager_->is_bot() || (!m->is_outgoing && dialog_id != get_my_dialog_id())) {
37263     return;
37264   }
37265 
37266   Dialog *d = nullptr;
37267   switch (dialog_id.get_type()) {
37268     case DialogType::User:
37269       d = get_dialog(dialog_id);
37270       break;
37271     case DialogType::Chat:
37272     case DialogType::Channel:
37273       break;
37274     case DialogType::SecretChat: {
37275       auto user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id());
37276       if (user_id.is_valid()) {
37277         d = get_dialog_force(DialogId(user_id), "update_has_outgoing_messages");
37278       }
37279       break;
37280     }
37281     default:
37282       UNREACHABLE();
37283   }
37284   if (d == nullptr || d->has_outgoing_messages) {
37285     return;
37286   }
37287 
37288   d->has_outgoing_messages = true;
37289   on_dialog_updated(dialog_id, "update_has_outgoing_messages");
37290 
37291   if (d->action_bar != nullptr && d->action_bar->on_outgoing_message()) {
37292     send_update_chat_action_bar(d);
37293   }
37294 }
37295 
continue_send_message(DialogId dialog_id,unique_ptr<Message> && m,uint64 log_event_id)37296 MessagesManager::Message *MessagesManager::continue_send_message(DialogId dialog_id, unique_ptr<Message> &&m,
37297                                                                  uint64 log_event_id) {
37298   CHECK(log_event_id != 0);
37299   CHECK(m != nullptr);
37300   CHECK(m->content != nullptr);
37301 
37302   Dialog *d = get_dialog_force(dialog_id, "continue_send_message");
37303   if (d == nullptr) {
37304     LOG(ERROR) << "Can't find " << dialog_id << " to continue send a message";
37305     binlog_erase(G()->td_db()->get_binlog(), log_event_id);
37306     return nullptr;
37307   }
37308   if (!have_input_peer(dialog_id, AccessRights::Read)) {
37309     binlog_erase(G()->td_db()->get_binlog(), log_event_id);
37310     return nullptr;
37311   }
37312 
37313   LOG(INFO) << "Continue to send " << m->message_id << " to " << dialog_id << " initially sent at " << m->send_date
37314             << " from binlog";
37315 
37316   d->was_opened = true;
37317 
37318   auto now = G()->unix_time();
37319   if (m->message_id.is_scheduled()) {
37320     set_message_id(m, get_next_yet_unsent_scheduled_message_id(d, m->date));
37321   } else {
37322     set_message_id(m, get_next_yet_unsent_message_id(d));
37323     m->date = now;
37324   }
37325   m->have_previous = true;
37326   m->have_next = true;
37327 
37328   bool need_update = false;
37329   bool need_update_dialog_pos = false;
37330   auto result_message =
37331       add_message_to_dialog(d, std::move(m), true, &need_update, &need_update_dialog_pos, "continue_send_message");
37332   CHECK(result_message != nullptr);
37333 
37334   if (result_message->message_id.is_scheduled()) {
37335     send_update_chat_has_scheduled_messages(d, false);
37336   }
37337 
37338   send_update_new_message(d, result_message);
37339   if (need_update_dialog_pos) {
37340     send_update_chat_last_message(d, "continue_send_message");
37341   }
37342 
37343   auto can_send_status = can_send_message(dialog_id);
37344   if (can_send_status.is_ok() && result_message->send_date < now - MAX_RESEND_DELAY &&
37345       dialog_id != get_my_dialog_id()) {
37346     can_send_status = Status::Error(400, "Message is too old to be re-sent automatically");
37347   }
37348   if (can_send_status.is_error()) {
37349     LOG(INFO) << "Can't continue to send a message to " << dialog_id << ": " << can_send_status.error();
37350 
37351     fail_send_message({dialog_id, result_message->message_id}, can_send_status.move_as_error());
37352     return nullptr;
37353   }
37354 
37355   return result_message;
37356 }
37357 
on_binlog_events(vector<BinlogEvent> && events)37358 void MessagesManager::on_binlog_events(vector<BinlogEvent> &&events) {
37359   for (auto &event : events) {
37360     CHECK(event.id_ != 0);
37361     switch (event.type_) {
37362       case LogEvent::HandlerType::SendMessage: {
37363         if (!G()->parameters().use_message_db) {
37364           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37365           break;
37366         }
37367 
37368         SendMessageLogEvent log_event;
37369         log_event_parse(log_event, event.data_).ensure();
37370 
37371         auto dialog_id = log_event.dialog_id;
37372         auto m = std::move(log_event.m_out);
37373         m->send_message_log_event_id = event.id_;
37374 
37375         if (m->content->get_type() == MessageContentType::Unsupported) {
37376           LOG(ERROR) << "Message content is invalid: " << format::as_hex_dump<4>(Slice(event.data_));
37377           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37378           continue;
37379         }
37380 
37381         Dependencies dependencies;
37382         add_dialog_dependencies(dependencies, dialog_id);
37383         add_message_dependencies(dependencies, m.get());
37384         resolve_dependencies_force(td_, dependencies, "SendMessageLogEvent");
37385 
37386         m->content =
37387             dup_message_content(td_, dialog_id, m->content.get(), MessageContentDupType::Send, MessageCopyOptions());
37388 
37389         auto result_message = continue_send_message(dialog_id, std::move(m), event.id_);
37390         if (result_message != nullptr) {
37391           do_send_message(dialog_id, result_message);
37392         }
37393 
37394         break;
37395       }
37396       case LogEvent::HandlerType::SendBotStartMessage: {
37397         if (!G()->parameters().use_message_db) {
37398           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37399           break;
37400         }
37401 
37402         SendBotStartMessageLogEvent log_event;
37403         log_event_parse(log_event, event.data_).ensure();
37404 
37405         auto dialog_id = log_event.dialog_id;
37406         auto m = std::move(log_event.m_out);
37407         m->send_message_log_event_id = event.id_;
37408 
37409         CHECK(m->content->get_type() == MessageContentType::Text);
37410 
37411         Dependencies dependencies;
37412         add_dialog_dependencies(dependencies, dialog_id);
37413         add_message_dependencies(dependencies, m.get());
37414         resolve_dependencies_force(td_, dependencies, "SendBotStartMessageLogEvent");
37415 
37416         auto bot_user_id = log_event.bot_user_id;
37417         if (!td_->contacts_manager_->have_user_force(bot_user_id)) {
37418           LOG(ERROR) << "Can't find bot " << bot_user_id;
37419           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37420           continue;
37421         }
37422 
37423         auto result_message = continue_send_message(dialog_id, std::move(m), event.id_);
37424         if (result_message != nullptr) {
37425           do_send_bot_start_message(bot_user_id, dialog_id, log_event.parameter, result_message);
37426         }
37427         break;
37428       }
37429       case LogEvent::HandlerType::SendInlineQueryResultMessage: {
37430         if (!G()->parameters().use_message_db) {
37431           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37432           break;
37433         }
37434 
37435         SendInlineQueryResultMessageLogEvent log_event;
37436         log_event_parse(log_event, event.data_).ensure();
37437 
37438         auto dialog_id = log_event.dialog_id;
37439         auto m = std::move(log_event.m_out);
37440         m->send_message_log_event_id = event.id_;
37441 
37442         if (m->content->get_type() == MessageContentType::Unsupported) {
37443           LOG(ERROR) << "Message content is invalid: " << format::as_hex_dump<4>(Slice(event.data_));
37444           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37445           continue;
37446         }
37447 
37448         Dependencies dependencies;
37449         add_dialog_dependencies(dependencies, dialog_id);
37450         add_message_dependencies(dependencies, m.get());
37451         resolve_dependencies_force(td_, dependencies, "SendInlineQueryResultMessageLogEvent");
37452 
37453         m->content = dup_message_content(td_, dialog_id, m->content.get(), MessageContentDupType::SendViaBot,
37454                                          MessageCopyOptions());
37455 
37456         auto result_message = continue_send_message(dialog_id, std::move(m), event.id_);
37457         if (result_message != nullptr) {
37458           do_send_inline_query_result_message(dialog_id, result_message, log_event.query_id, log_event.result_id);
37459         }
37460         break;
37461       }
37462       case LogEvent::HandlerType::SendScreenshotTakenNotificationMessage: {
37463         if (!G()->parameters().use_message_db) {
37464           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37465           break;
37466         }
37467 
37468         SendScreenshotTakenNotificationMessageLogEvent log_event;
37469         log_event_parse(log_event, event.data_).ensure();
37470 
37471         auto dialog_id = log_event.dialog_id;
37472         auto m = std::move(log_event.m_out);
37473         m->send_message_log_event_id = 0;  // to not allow event deletion by message deletion
37474 
37475         CHECK(m->content->get_type() == MessageContentType::ScreenshotTaken);
37476 
37477         Dependencies dependencies;
37478         add_dialog_dependencies(dependencies, dialog_id);
37479         add_message_dependencies(dependencies, m.get());
37480         resolve_dependencies_force(td_, dependencies, "SendScreenshotTakenNotificationMessageLogEvent");
37481 
37482         auto result_message = continue_send_message(dialog_id, std::move(m), event.id_);
37483         if (result_message != nullptr) {
37484           do_send_screenshot_taken_notification_message(dialog_id, result_message, event.id_);
37485         }
37486         break;
37487       }
37488       case LogEvent::HandlerType::ForwardMessages: {
37489         if (!G()->parameters().use_message_db) {
37490           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37491           continue;
37492         }
37493 
37494         ForwardMessagesLogEvent log_event;
37495         log_event_parse(log_event, event.data_).ensure();
37496 
37497         auto to_dialog_id = log_event.to_dialog_id;
37498         auto from_dialog_id = log_event.from_dialog_id;
37499         auto messages = std::move(log_event.messages_out);
37500 
37501         Dependencies dependencies;
37502         add_dialog_dependencies(dependencies, to_dialog_id);
37503         add_dialog_dependencies(dependencies, from_dialog_id);
37504         for (auto &m : messages) {
37505           add_message_dependencies(dependencies, m.get());
37506         }
37507         resolve_dependencies_force(td_, dependencies, "ForwardMessagesLogEvent");
37508 
37509         Dialog *to_dialog = get_dialog_force(to_dialog_id, "ForwardMessagesLogEvent to");
37510         if (to_dialog == nullptr) {
37511           LOG(ERROR) << "Can't find " << to_dialog_id << " to forward messages to";
37512           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37513           continue;
37514         }
37515         Dialog *from_dialog = get_dialog_force(from_dialog_id, "ForwardMessagesLogEvent from");
37516         if (from_dialog == nullptr) {
37517           LOG(ERROR) << "Can't find " << from_dialog_id << " to forward messages from";
37518           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37519           continue;
37520         }
37521 
37522         to_dialog->was_opened = true;
37523 
37524         auto now = G()->unix_time();
37525         if (!have_input_peer(from_dialog_id, AccessRights::Read) || can_send_message(to_dialog_id).is_error() ||
37526             messages.empty() ||
37527             (messages[0]->send_date < now - MAX_RESEND_DELAY && to_dialog_id != get_my_dialog_id())) {
37528           LOG(WARNING) << "Can't continue forwarding " << messages.size() << " message(s) to " << to_dialog_id;
37529           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37530           continue;
37531         }
37532 
37533         LOG(INFO) << "Continue to forward " << messages.size() << " message(s) to " << to_dialog_id << " from binlog";
37534 
37535         bool need_update = false;
37536         bool need_update_dialog_pos = false;
37537         vector<Message *> forwarded_messages;
37538         for (auto &m : messages) {
37539           if (m->message_id.is_scheduled()) {
37540             set_message_id(m, get_next_yet_unsent_scheduled_message_id(to_dialog, m->date));
37541           } else {
37542             set_message_id(m, get_next_yet_unsent_message_id(to_dialog));
37543             m->date = now;
37544           }
37545           m->content = dup_message_content(td_, to_dialog_id, m->content.get(), MessageContentDupType::Forward,
37546                                            MessageCopyOptions());
37547           CHECK(m->content != nullptr);
37548           m->have_previous = true;
37549           m->have_next = true;
37550 
37551           forwarded_messages.push_back(add_message_to_dialog(to_dialog, std::move(m), true, &need_update,
37552                                                              &need_update_dialog_pos, "forward message again"));
37553           send_update_new_message(to_dialog, forwarded_messages.back());
37554         }
37555 
37556         send_update_chat_has_scheduled_messages(to_dialog, false);
37557 
37558         if (need_update_dialog_pos) {
37559           send_update_chat_last_message(to_dialog, "on_reforward_message");
37560         }
37561 
37562         do_forward_messages(to_dialog_id, from_dialog_id, forwarded_messages, log_event.message_ids, event.id_);
37563         break;
37564       }
37565       case LogEvent::HandlerType::DeleteMessage: {
37566         if (!G()->parameters().use_message_db) {
37567           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37568           break;
37569         }
37570 
37571         DeleteMessageLogEvent log_event;
37572         log_event_parse(log_event, event.data_).ensure();
37573         log_event.id_ = event.id_;
37574 
37575         Dialog *d = get_dialog_force(log_event.full_message_id_.get_dialog_id(), "DeleteMessageLogEvent");
37576         if (d != nullptr) {
37577           auto message_id = log_event.full_message_id_.get_message_id();
37578           if (message_id.is_valid_scheduled() && message_id.is_scheduled_server()) {
37579             d->deleted_scheduled_server_message_ids.insert(message_id.get_scheduled_server_message_id());
37580           } else {
37581             d->deleted_message_ids.insert(message_id);
37582           }
37583         }
37584 
37585         do_delete_message_log_event(log_event);
37586         break;
37587       }
37588       case LogEvent::HandlerType::DeleteMessagesOnServer: {
37589         if (!G()->parameters().use_message_db) {
37590           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37591           break;
37592         }
37593 
37594         DeleteMessagesOnServerLogEvent log_event;
37595         log_event_parse(log_event, event.data_).ensure();
37596 
37597         auto dialog_id = log_event.dialog_id_;
37598         Dialog *d = get_dialog_force(dialog_id, "DeleteMessagesOnServerLogEvent");
37599         if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) {
37600           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37601           break;
37602         }
37603 
37604         d->deleted_message_ids.insert(log_event.message_ids_.begin(), log_event.message_ids_.end());
37605 
37606         delete_messages_on_server(dialog_id, std::move(log_event.message_ids_), log_event.revoke_, event.id_, Auto());
37607         break;
37608       }
37609       case LogEvent::HandlerType::DeleteScheduledMessagesOnServer: {
37610         if (!G()->parameters().use_message_db) {
37611           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37612           break;
37613         }
37614 
37615         DeleteScheduledMessagesOnServerLogEvent log_event;
37616         log_event_parse(log_event, event.data_).ensure();
37617 
37618         auto dialog_id = log_event.dialog_id_;
37619         Dialog *d = get_dialog_force(dialog_id, "DeleteScheduledMessagesOnServerLogEvent");
37620         if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) {
37621           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37622           break;
37623         }
37624 
37625         for (auto message_id : log_event.message_ids_) {
37626           CHECK(message_id.is_scheduled_server());
37627           d->deleted_scheduled_server_message_ids.insert(message_id.get_scheduled_server_message_id());
37628         }
37629 
37630         delete_scheduled_messages_on_server(dialog_id, std::move(log_event.message_ids_), event.id_, Auto());
37631         break;
37632       }
37633       case LogEvent::HandlerType::DeleteDialogHistoryOnServer: {
37634         if (!G()->parameters().use_message_db) {
37635           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37636           break;
37637         }
37638 
37639         DeleteDialogHistoryOnServerLogEvent log_event;
37640         log_event_parse(log_event, event.data_).ensure();
37641 
37642         auto dialog_id = log_event.dialog_id_;
37643         Dialog *d = get_dialog_force(dialog_id, "DeleteDialogHistoryOnServerLogEvent");
37644         if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) {
37645           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37646           break;
37647         }
37648 
37649         delete_dialog_history_on_server(dialog_id, log_event.max_message_id_, log_event.remove_from_dialog_list_,
37650                                         log_event.revoke_, true, event.id_, Auto());
37651         break;
37652       }
37653       case LogEvent::HandlerType::DeleteAllCallMessagesOnServer: {
37654         DeleteAllCallMessagesOnServerLogEvent log_event;
37655         log_event_parse(log_event, event.data_).ensure();
37656 
37657         delete_all_call_messages_on_server(log_event.revoke_, event.id_, Auto());
37658         break;
37659       }
37660       case LogEvent::HandlerType::BlockMessageSenderFromRepliesOnServer: {
37661         BlockMessageSenderFromRepliesOnServerLogEvent log_event;
37662         log_event_parse(log_event, event.data_).ensure();
37663 
37664         block_message_sender_from_replies_on_server(log_event.message_id_, log_event.delete_message_,
37665                                                     log_event.delete_all_messages_, log_event.report_spam_, event.id_,
37666                                                     Auto());
37667         break;
37668       }
37669       case LogEvent::HandlerType::DeleteAllChannelMessagesFromSenderOnServer: {
37670         if (!G()->parameters().use_chat_info_db) {
37671           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37672           break;
37673         }
37674 
37675         DeleteAllChannelMessagesFromSenderOnServerLogEvent log_event;
37676         log_event_parse(log_event, event.data_).ensure();
37677 
37678         auto channel_id = log_event.channel_id_;
37679         if (!td_->contacts_manager_->have_channel_force(channel_id)) {
37680           LOG(ERROR) << "Can't find " << channel_id;
37681           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37682           break;
37683         }
37684 
37685         auto sender_dialog_id = log_event.sender_dialog_id_;
37686         if (!td_->messages_manager_->have_dialog_info_force(sender_dialog_id) ||
37687             !td_->messages_manager_->have_input_peer(sender_dialog_id, AccessRights::Know)) {
37688           LOG(ERROR) << "Can't find " << sender_dialog_id;
37689           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37690           break;
37691         }
37692 
37693         delete_all_channel_messages_by_sender_on_server(channel_id, sender_dialog_id, event.id_, Auto());
37694         break;
37695       }
37696       case LogEvent::HandlerType::DeleteDialogMessagesByDateOnServer: {
37697         if (!G()->parameters().use_message_db) {
37698           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37699           break;
37700         }
37701 
37702         DeleteDialogMessagesByDateOnServerLogEvent log_event;
37703         log_event_parse(log_event, event.data_).ensure();
37704 
37705         auto dialog_id = log_event.dialog_id_;
37706         Dialog *d = get_dialog_force(dialog_id, "DeleteDialogMessagesByDateOnServerLogEvent");
37707         if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) {
37708           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37709           break;
37710         }
37711 
37712         delete_dialog_messages_by_date_on_server(dialog_id, log_event.min_date_, log_event.max_date_, log_event.revoke_,
37713                                                  event.id_, Auto());
37714         break;
37715       }
37716       case LogEvent::HandlerType::ReadHistoryOnServer: {
37717         if (!G()->parameters().use_message_db) {
37718           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37719           break;
37720         }
37721 
37722         ReadHistoryOnServerLogEvent log_event;
37723         log_event_parse(log_event, event.data_).ensure();
37724 
37725         auto dialog_id = log_event.dialog_id_;
37726         Dialog *d = get_dialog_force(dialog_id, "ReadHistoryOnServerLogEvent");
37727         if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) {
37728           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37729           break;
37730         }
37731         if (d->read_history_log_event_ids[0].log_event_id != 0) {
37732           // we need only latest read history event
37733           binlog_erase(G()->td_db()->get_binlog(), d->read_history_log_event_ids[0].log_event_id);
37734         }
37735         d->read_history_log_event_ids[0].log_event_id = event.id_;
37736 
37737         read_history_on_server_impl(d, log_event.max_message_id_);
37738         break;
37739       }
37740       case LogEvent::HandlerType::ReadHistoryInSecretChat: {
37741         ReadHistoryInSecretChatLogEvent log_event;
37742         log_event_parse(log_event, event.data_).ensure();
37743 
37744         auto dialog_id = log_event.dialog_id_;
37745         CHECK(dialog_id.get_type() == DialogType::SecretChat);
37746         if (!td_->contacts_manager_->have_secret_chat_force(dialog_id.get_secret_chat_id())) {
37747           LOG(ERROR) << "Have no info about " << dialog_id;
37748           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37749           break;
37750         }
37751         force_create_dialog(dialog_id, "ReadHistoryInSecretChatLogEvent");
37752         Dialog *d = get_dialog(dialog_id);
37753         if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) {
37754           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37755           break;
37756         }
37757         if (d->read_history_log_event_ids[0].log_event_id != 0) {
37758           // we need only latest read history event
37759           binlog_erase(G()->td_db()->get_binlog(), d->read_history_log_event_ids[0].log_event_id);
37760         }
37761         d->read_history_log_event_ids[0].log_event_id = event.id_;
37762         d->last_read_inbox_message_date = log_event.max_date_;
37763 
37764         read_history_on_server_impl(d, MessageId());
37765         break;
37766       }
37767       case LogEvent::HandlerType::ReadMessageThreadHistoryOnServer: {
37768         if (!G()->parameters().use_message_db) {
37769           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37770           break;
37771         }
37772 
37773         ReadMessageThreadHistoryOnServerLogEvent log_event;
37774         log_event_parse(log_event, event.data_).ensure();
37775 
37776         auto dialog_id = log_event.dialog_id_;
37777         Dialog *d = get_dialog_force(dialog_id, "ReadMessageThreadHistoryOnServerLogEvent");
37778         if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) {
37779           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37780           break;
37781         }
37782         auto top_thread_message_id = log_event.top_thread_message_id_;
37783         if (d->read_history_log_event_ids[top_thread_message_id.get()].log_event_id != 0) {
37784           // we need only latest read history event
37785           binlog_erase(G()->td_db()->get_binlog(),
37786                        d->read_history_log_event_ids[top_thread_message_id.get()].log_event_id);
37787         }
37788         d->read_history_log_event_ids[top_thread_message_id.get()].log_event_id = event.id_;
37789 
37790         read_message_thread_history_on_server_impl(d, top_thread_message_id, log_event.max_message_id_);
37791         break;
37792       }
37793       case LogEvent::HandlerType::ReadMessageContentsOnServer: {
37794         if (!G()->parameters().use_message_db) {
37795           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37796           break;
37797         }
37798 
37799         ReadMessageContentsOnServerLogEvent log_event;
37800         log_event_parse(log_event, event.data_).ensure();
37801 
37802         auto dialog_id = log_event.dialog_id_;
37803         Dialog *d = get_dialog_force(dialog_id, "ReadMessageContentsOnServerLogEvent");
37804         if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) {
37805           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37806           break;
37807         }
37808 
37809         read_message_contents_on_server(dialog_id, std::move(log_event.message_ids_), event.id_, Auto());
37810         break;
37811       }
37812       case LogEvent::HandlerType::ReadAllDialogMentionsOnServer: {
37813         if (!G()->parameters().use_message_db) {
37814           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37815           break;
37816         }
37817 
37818         ReadAllDialogMentionsOnServerLogEvent log_event;
37819         log_event_parse(log_event, event.data_).ensure();
37820 
37821         auto dialog_id = log_event.dialog_id_;
37822         Dialog *d = get_dialog_force(dialog_id, "ReadAllDialogMentionsOnServerLogEvent");
37823         if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) {
37824           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37825           break;
37826         }
37827 
37828         read_all_dialog_mentions_on_server(dialog_id, event.id_, Promise<Unit>());
37829         break;
37830       }
37831       case LogEvent::HandlerType::ToggleDialogIsPinnedOnServer: {
37832         if (!G()->parameters().use_message_db) {
37833           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37834           break;
37835         }
37836 
37837         ToggleDialogIsPinnedOnServerLogEvent log_event;
37838         log_event_parse(log_event, event.data_).ensure();
37839 
37840         auto dialog_id = log_event.dialog_id_;
37841         Dialog *d = get_dialog_force(dialog_id, "ToggleDialogIsPinnedOnServerLogEvent");
37842         if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) {
37843           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37844           break;
37845         }
37846 
37847         toggle_dialog_is_pinned_on_server(dialog_id, log_event.is_pinned_, event.id_);
37848         break;
37849       }
37850       case LogEvent::HandlerType::ReorderPinnedDialogsOnServer: {
37851         if (!G()->parameters().use_message_db) {
37852           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37853           break;
37854         }
37855 
37856         ReorderPinnedDialogsOnServerLogEvent log_event;
37857         log_event_parse(log_event, event.data_).ensure();
37858 
37859         vector<DialogId> dialog_ids;
37860         for (auto &dialog_id : log_event.dialog_ids_) {
37861           Dialog *d = get_dialog_force(dialog_id, "ReorderPinnedDialogsOnServerLogEvent");
37862           if (d != nullptr && have_input_peer(dialog_id, AccessRights::Read)) {
37863             dialog_ids.push_back(dialog_id);
37864           }
37865         }
37866         if (dialog_ids.empty()) {
37867           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37868           break;
37869         }
37870 
37871         reorder_pinned_dialogs_on_server(log_event.folder_id_, dialog_ids, event.id_);
37872         break;
37873       }
37874       case LogEvent::HandlerType::ToggleDialogIsMarkedAsUnreadOnServer: {
37875         if (!G()->parameters().use_message_db) {
37876           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37877           break;
37878         }
37879 
37880         ToggleDialogIsMarkedAsUnreadOnServerLogEvent log_event;
37881         log_event_parse(log_event, event.data_).ensure();
37882 
37883         auto dialog_id = log_event.dialog_id_;
37884         bool have_info = dialog_id.get_type() == DialogType::User
37885                              ? td_->contacts_manager_->have_user_force(dialog_id.get_user_id())
37886                              : have_dialog_force(dialog_id, "ToggleDialogIsMarkedAsUnreadOnServerLogEvent");
37887         if (!have_info || !have_input_peer(dialog_id, AccessRights::Read)) {
37888           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37889           break;
37890         }
37891 
37892         toggle_dialog_is_marked_as_unread_on_server(dialog_id, log_event.is_marked_as_unread_, event.id_);
37893         break;
37894       }
37895       case LogEvent::HandlerType::ToggleDialogIsBlockedOnServer: {
37896         if (!G()->parameters().use_message_db) {
37897           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37898           break;
37899         }
37900 
37901         ToggleDialogIsBlockedOnServerLogEvent log_event;
37902         log_event_parse(log_event, event.data_).ensure();
37903 
37904         auto dialog_id = log_event.dialog_id_;
37905         if (dialog_id.get_type() == DialogType::SecretChat || !have_dialog_info_force(dialog_id) ||
37906             !have_input_peer(dialog_id, AccessRights::Know)) {
37907           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37908           break;
37909         }
37910 
37911         toggle_dialog_is_blocked_on_server(dialog_id, log_event.is_blocked_, event.id_);
37912         break;
37913       }
37914       case LogEvent::HandlerType::SaveDialogDraftMessageOnServer: {
37915         if (!G()->parameters().use_message_db) {
37916           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37917           break;
37918         }
37919 
37920         SaveDialogDraftMessageOnServerLogEvent log_event;
37921         log_event_parse(log_event, event.data_).ensure();
37922 
37923         auto dialog_id = log_event.dialog_id_;
37924         Dialog *d = get_dialog_force(dialog_id, "SaveDialogDraftMessageOnServerLogEvent");
37925         if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Write)) {
37926           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37927           break;
37928         }
37929         d->save_draft_message_log_event_id.log_event_id = event.id_;
37930 
37931         save_dialog_draft_message_on_server(dialog_id);
37932         break;
37933       }
37934       case LogEvent::HandlerType::UpdateDialogNotificationSettingsOnServer: {
37935         if (!G()->parameters().use_message_db) {
37936           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37937           break;
37938         }
37939 
37940         UpdateDialogNotificationSettingsOnServerLogEvent log_event;
37941         log_event_parse(log_event, event.data_).ensure();
37942 
37943         auto dialog_id = log_event.dialog_id_;
37944         Dialog *d = get_dialog_force(dialog_id, "UpdateDialogNotificationSettingsOnServerLogEvent");
37945         if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) {
37946           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37947           break;
37948         }
37949         d->save_notification_settings_log_event_id.log_event_id = event.id_;
37950 
37951         update_dialog_notification_settings_on_server(dialog_id, true);
37952         break;
37953       }
37954       case LogEvent::HandlerType::UpdateScopeNotificationSettingsOnServer: {
37955         UpdateScopeNotificationSettingsOnServerLogEvent log_event;
37956         log_event_parse(log_event, event.data_).ensure();
37957 
37958         update_scope_notification_settings_on_server(log_event.scope_, event.id_);
37959         break;
37960       }
37961       case LogEvent::HandlerType::ResetAllNotificationSettingsOnServer: {
37962         ResetAllNotificationSettingsOnServerLogEvent log_event;
37963         log_event_parse(log_event, event.data_).ensure();
37964 
37965         reset_all_notification_settings_on_server(event.id_);
37966         break;
37967       }
37968       case LogEvent::HandlerType::ToggleDialogReportSpamStateOnServer: {
37969         if (!G()->parameters().use_message_db) {
37970           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37971           break;
37972         }
37973 
37974         ToggleDialogReportSpamStateOnServerLogEvent log_event;
37975         log_event_parse(log_event, event.data_).ensure();
37976 
37977         auto dialog_id = log_event.dialog_id_;
37978         Dialog *d = get_dialog_force(dialog_id, "ToggleDialogReportSpamStateOnServerLogEvent");
37979         if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) {
37980           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37981           break;
37982         }
37983 
37984         toggle_dialog_report_spam_state_on_server(dialog_id, log_event.is_spam_dialog_, event.id_, Promise<Unit>());
37985         break;
37986       }
37987       case LogEvent::HandlerType::SetDialogFolderIdOnServer: {
37988         if (!G()->parameters().use_message_db) {
37989           binlog_erase(G()->td_db()->get_binlog(), event.id_);
37990           break;
37991         }
37992 
37993         SetDialogFolderIdOnServerLogEvent log_event;
37994         log_event_parse(log_event, event.data_).ensure();
37995 
37996         auto dialog_id = log_event.dialog_id_;
37997         Dialog *d = get_dialog_force(dialog_id, "SetDialogFolderIdOnServerLogEvent");
37998         if (d == nullptr || !have_input_peer(dialog_id, AccessRights::Read)) {
37999           binlog_erase(G()->td_db()->get_binlog(), event.id_);
38000           break;
38001         }
38002         d->set_folder_id_log_event_id.log_event_id = event.id_;
38003 
38004         set_dialog_folder_id(d, log_event.folder_id_);
38005 
38006         set_dialog_folder_id_on_server(dialog_id, true);
38007         break;
38008       }
38009       case LogEvent::HandlerType::RegetDialog: {
38010         if (!G()->parameters().use_message_db) {
38011           binlog_erase(G()->td_db()->get_binlog(), event.id_);
38012           break;
38013         }
38014 
38015         RegetDialogLogEvent log_event;
38016         log_event_parse(log_event, event.data_).ensure();
38017 
38018         auto dialog_id = log_event.dialog_id_;
38019         Dependencies dependencies;
38020         add_dialog_dependencies(dependencies, dialog_id);
38021         resolve_dependencies_force(td_, dependencies, "RegetDialogLogEvent");
38022 
38023         get_dialog_force(dialog_id, "RegetDialogLogEvent");  // load it if exists
38024 
38025         if (!have_input_peer(dialog_id, AccessRights::Read)) {
38026           binlog_erase(G()->td_db()->get_binlog(), event.id_);
38027           break;
38028         }
38029 
38030         send_get_dialog_query(dialog_id, Auto(), event.id_, "RegetDialogLogEvent");
38031         break;
38032       }
38033       case LogEvent::HandlerType::UnpinAllDialogMessagesOnServer: {
38034         if (!G()->parameters().use_message_db) {
38035           binlog_erase(G()->td_db()->get_binlog(), event.id_);
38036           break;
38037         }
38038 
38039         UnpinAllDialogMessagesOnServerLogEvent log_event;
38040         log_event_parse(log_event, event.data_).ensure();
38041 
38042         unpin_all_dialog_messages_on_server(log_event.dialog_id_, event.id_, Auto());
38043         break;
38044       }
38045       case LogEvent::HandlerType::GetChannelDifference: {
38046         if (G()->ignore_background_updates()) {
38047           binlog_erase(G()->td_db()->get_binlog(), event.id_);
38048           break;
38049         }
38050 
38051         GetChannelDifferenceLogEvent log_event;
38052         log_event_parse(log_event, event.data_).ensure();
38053 
38054         DialogId dialog_id(log_event.channel_id);
38055         LOG(INFO) << "Continue to run getChannelDifference in " << dialog_id;
38056         get_channel_difference_to_log_event_id_.emplace(dialog_id, event.id_);
38057         do_get_channel_difference(
38058             dialog_id, load_channel_pts(dialog_id), true,
38059             telegram_api::make_object<telegram_api::inputChannel>(log_event.channel_id.get(), log_event.access_hash),
38060             "LogEvent::HandlerType::GetChannelDifference");
38061         break;
38062       }
38063       default:
38064         LOG(FATAL) << "Unsupported log event type " << event.type_;
38065     }
38066   }
38067 }
38068 
add_recently_found_dialog(DialogId dialog_id)38069 Status MessagesManager::add_recently_found_dialog(DialogId dialog_id) {
38070   if (!have_dialog_force(dialog_id, "add_recently_found_dialog")) {
38071     return Status::Error(400, "Chat not found");
38072   }
38073   recently_found_dialogs_.add_dialog(dialog_id);
38074   return Status::OK();
38075 }
38076 
remove_recently_found_dialog(DialogId dialog_id)38077 Status MessagesManager::remove_recently_found_dialog(DialogId dialog_id) {
38078   if (!have_dialog_force(dialog_id, "remove_recently_found_dialog")) {
38079     return Status::Error(400, "Chat not found");
38080   }
38081   recently_found_dialogs_.remove_dialog(dialog_id);
38082   return Status::OK();
38083 }
38084 
clear_recently_found_dialogs()38085 void MessagesManager::clear_recently_found_dialogs() {
38086   recently_found_dialogs_.clear_dialogs();
38087 }
38088 
suffix_load_loop(Dialog * d)38089 void MessagesManager::suffix_load_loop(Dialog *d) {
38090   if (d->suffix_load_has_query_) {
38091     return;
38092   }
38093 
38094   if (d->suffix_load_queries_.empty()) {
38095     return;
38096   }
38097   CHECK(!d->suffix_load_done_);
38098 
38099   auto dialog_id = d->dialog_id;
38100   auto from_message_id = d->suffix_load_first_message_id_;
38101   LOG(INFO) << "Send suffix load query in " << dialog_id << " from " << from_message_id;
38102   auto promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_id](Result<Unit> result) {
38103     send_closure(actor_id, &MessagesManager::suffix_load_query_ready, dialog_id);
38104   });
38105   d->suffix_load_has_query_ = true;
38106   d->suffix_load_query_message_id_ = from_message_id;
38107   if (from_message_id.is_valid()) {
38108     get_history_impl(d, from_message_id, -1, 100, true, true, std::move(promise));
38109   } else {
38110     CHECK(from_message_id == MessageId());
38111     get_history_from_the_end_impl(d, true, true, std::move(promise));
38112   }
38113 }
38114 
suffix_load_update_first_message_id(Dialog * d)38115 void MessagesManager::suffix_load_update_first_message_id(Dialog *d) {
38116   if (!d->suffix_load_first_message_id_.is_valid()) {
38117     if (!d->last_message_id.is_valid()) {
38118       return;
38119     }
38120 
38121     d->suffix_load_first_message_id_ = d->last_message_id;
38122   }
38123   auto it = MessagesConstIterator(d, d->suffix_load_first_message_id_);
38124   CHECK(*it != nullptr);
38125   CHECK((*it)->message_id == d->suffix_load_first_message_id_);
38126   while ((*it)->have_previous) {
38127     --it;
38128   }
38129   d->suffix_load_first_message_id_ = (*it)->message_id;
38130 }
38131 
suffix_load_query_ready(DialogId dialog_id)38132 void MessagesManager::suffix_load_query_ready(DialogId dialog_id) {
38133   LOG(INFO) << "Finished suffix load query in " << dialog_id;
38134   auto *d = get_dialog(dialog_id);
38135   CHECK(d != nullptr);
38136   bool is_unchanged = d->suffix_load_first_message_id_ == d->suffix_load_query_message_id_;
38137   suffix_load_update_first_message_id(d);
38138   if (is_unchanged && d->suffix_load_first_message_id_ == d->suffix_load_query_message_id_) {
38139     LOG(INFO) << "Finished suffix load in " << dialog_id;
38140     d->suffix_load_done_ = true;
38141   }
38142   d->suffix_load_has_query_ = false;
38143 
38144   // Remove ready queries
38145   auto *m = get_message_force(d, d->suffix_load_first_message_id_, "suffix_load_query_ready");
38146   auto ready_it = std::partition(d->suffix_load_queries_.begin(), d->suffix_load_queries_.end(),
38147                                  [&](auto &value) { return !(d->suffix_load_done_ || value.second(m)); });
38148   for (auto it = ready_it; it != d->suffix_load_queries_.end(); ++it) {
38149     it->first.set_value(Unit());
38150   }
38151   d->suffix_load_queries_.erase(ready_it, d->suffix_load_queries_.end());
38152 
38153   suffix_load_loop(d);
38154 }
38155 
suffix_load_add_query(Dialog * d,std::pair<Promise<>,std::function<bool (const Message *)>> query)38156 void MessagesManager::suffix_load_add_query(Dialog *d,
38157                                             std::pair<Promise<>, std::function<bool(const Message *)>> query) {
38158   suffix_load_update_first_message_id(d);
38159   auto *m = get_message_force(d, d->suffix_load_first_message_id_, "suffix_load_add_query");
38160   if (d->suffix_load_done_ || query.second(m)) {
38161     query.first.set_value(Unit());
38162   } else {
38163     d->suffix_load_queries_.emplace_back(std::move(query));
38164     suffix_load_loop(d);
38165   }
38166 }
38167 
suffix_load_till_date(Dialog * d,int32 date,Promise<> promise)38168 void MessagesManager::suffix_load_till_date(Dialog *d, int32 date, Promise<> promise) {
38169   LOG(INFO) << "Load suffix of " << d->dialog_id << " till date " << date;
38170   auto condition = [date](const Message *m) {
38171     return m != nullptr && m->date < date;
38172   };
38173   suffix_load_add_query(d, std::make_pair(std::move(promise), std::move(condition)));
38174 }
38175 
suffix_load_till_message_id(Dialog * d,MessageId message_id,Promise<> promise)38176 void MessagesManager::suffix_load_till_message_id(Dialog *d, MessageId message_id, Promise<> promise) {
38177   LOG(INFO) << "Load suffix of " << d->dialog_id << " till " << message_id;
38178   auto condition = [message_id](const Message *m) {
38179     return m != nullptr && m->message_id < message_id;
38180   };
38181   suffix_load_add_query(d, std::make_pair(std::move(promise), std::move(condition)));
38182 }
38183 
set_poll_answer(FullMessageId full_message_id,vector<int32> && option_ids,Promise<Unit> && promise)38184 void MessagesManager::set_poll_answer(FullMessageId full_message_id, vector<int32> &&option_ids,
38185                                       Promise<Unit> &&promise) {
38186   auto m = get_message_force(full_message_id, "set_poll_answer");
38187   if (m == nullptr) {
38188     return promise.set_error(Status::Error(400, "Message not found"));
38189   }
38190   if (!have_input_peer(full_message_id.get_dialog_id(), AccessRights::Read)) {
38191     return promise.set_error(Status::Error(400, "Can't access the chat"));
38192   }
38193   if (m->content->get_type() != MessageContentType::Poll) {
38194     return promise.set_error(Status::Error(400, "Message is not a poll"));
38195   }
38196   if (m->message_id.is_scheduled()) {
38197     return promise.set_error(Status::Error(400, "Can't answer polls from scheduled messages"));
38198   }
38199   if (!m->message_id.is_server()) {
38200     return promise.set_error(Status::Error(400, "Poll can't be answered"));
38201   }
38202 
38203   set_message_content_poll_answer(td_, m->content.get(), full_message_id, std::move(option_ids), std::move(promise));
38204 }
38205 
get_poll_voters(FullMessageId full_message_id,int32 option_id,int32 offset,int32 limit,Promise<std::pair<int32,vector<UserId>>> && promise)38206 void MessagesManager::get_poll_voters(FullMessageId full_message_id, int32 option_id, int32 offset, int32 limit,
38207                                       Promise<std::pair<int32, vector<UserId>>> &&promise) {
38208   auto m = get_message_force(full_message_id, "get_poll_voters");
38209   if (m == nullptr) {
38210     return promise.set_error(Status::Error(400, "Message not found"));
38211   }
38212   if (!have_input_peer(full_message_id.get_dialog_id(), AccessRights::Read)) {
38213     return promise.set_error(Status::Error(400, "Can't access the chat"));
38214   }
38215   if (m->content->get_type() != MessageContentType::Poll) {
38216     return promise.set_error(Status::Error(400, "Message is not a poll"));
38217   }
38218   if (m->message_id.is_scheduled()) {
38219     return promise.set_error(Status::Error(400, "Can't get poll results from scheduled messages"));
38220   }
38221   if (!m->message_id.is_server()) {
38222     return promise.set_error(Status::Error(400, "Poll results can't be received"));
38223   }
38224 
38225   get_message_content_poll_voters(td_, m->content.get(), full_message_id, option_id, offset, limit, std::move(promise));
38226 }
38227 
stop_poll(FullMessageId full_message_id,td_api::object_ptr<td_api::ReplyMarkup> && reply_markup,Promise<Unit> && promise)38228 void MessagesManager::stop_poll(FullMessageId full_message_id, td_api::object_ptr<td_api::ReplyMarkup> &&reply_markup,
38229                                 Promise<Unit> &&promise) {
38230   auto m = get_message_force(full_message_id, "stop_poll");
38231   if (m == nullptr) {
38232     return promise.set_error(Status::Error(400, "Message not found"));
38233   }
38234   if (!have_input_peer(full_message_id.get_dialog_id(), AccessRights::Read)) {
38235     return promise.set_error(Status::Error(400, "Can't access the chat"));
38236   }
38237   if (m->content->get_type() != MessageContentType::Poll) {
38238     return promise.set_error(Status::Error(400, "Message is not a poll"));
38239   }
38240   if (get_message_content_poll_is_closed(td_, m->content.get())) {
38241     return promise.set_error(Status::Error(400, "Poll has already been closed"));
38242   }
38243   if (!can_edit_message(full_message_id.get_dialog_id(), m, true)) {
38244     return promise.set_error(Status::Error(400, "Poll can't be stopped"));
38245   }
38246   if (m->message_id.is_scheduled()) {
38247     return promise.set_error(Status::Error(400, "Can't stop polls from scheduled messages"));
38248   }
38249   if (!m->message_id.is_server()) {
38250     return promise.set_error(Status::Error(400, "Poll can't be stopped"));
38251   }
38252 
38253   auto r_new_reply_markup = get_reply_markup(std::move(reply_markup), td_->auth_manager_->is_bot(), true, false,
38254                                              has_message_sender_user_id(full_message_id.get_dialog_id(), m));
38255   if (r_new_reply_markup.is_error()) {
38256     return promise.set_error(r_new_reply_markup.move_as_error());
38257   }
38258 
38259   stop_message_content_poll(td_, m->content.get(), full_message_id, r_new_reply_markup.move_as_ok(),
38260                             std::move(promise));
38261 }
38262 
get_invoice_message_id(FullMessageId full_message_id)38263 Result<ServerMessageId> MessagesManager::get_invoice_message_id(FullMessageId full_message_id) {
38264   auto m = get_message_force(full_message_id, "get_invoice_message_id");
38265   if (m == nullptr) {
38266     return Status::Error(400, "Message not found");
38267   }
38268   if (m->content->get_type() != MessageContentType::Invoice) {
38269     return Status::Error(400, "Message has no invoice");
38270   }
38271   if (m->message_id.is_scheduled()) {
38272     return Status::Error(400, "Wrong scheduled message identifier");
38273   }
38274   if (!m->message_id.is_server()) {
38275     return Status::Error(400, "Wrong message identifier");
38276   }
38277   if (m->reply_markup == nullptr || m->reply_markup->inline_keyboard.empty() ||
38278       m->reply_markup->inline_keyboard[0].empty() ||
38279       m->reply_markup->inline_keyboard[0][0].type != InlineKeyboardButton::Type::Buy) {
38280     return Status::Error(400, "Message has no Pay button");
38281   }
38282 
38283   return m->message_id.get_server_message_id();
38284 }
38285 
get_payment_successful_message_id(FullMessageId full_message_id)38286 Result<ServerMessageId> MessagesManager::get_payment_successful_message_id(FullMessageId full_message_id) {
38287   auto m = get_message_force(full_message_id, "get_payment_successful_message_id");
38288   if (m == nullptr) {
38289     return Status::Error(400, "Message not found");
38290   }
38291   if (m->content->get_type() != MessageContentType::PaymentSuccessful) {
38292     return Status::Error(400, "Message has wrong type");
38293   }
38294   if (m->message_id.is_scheduled()) {
38295     return Status::Error(400, "Wrong scheduled message identifier");
38296   }
38297   if (!m->message_id.is_server()) {
38298     return Status::Error(400, "Wrong message identifier");
38299   }
38300 
38301   return m->message_id.get_server_message_id();
38302 }
38303 
remove_sponsored_dialog()38304 void MessagesManager::remove_sponsored_dialog() {
38305   set_sponsored_dialog(DialogId(), DialogSource());
38306 }
38307 
on_get_sponsored_dialog(tl_object_ptr<telegram_api::Peer> peer,DialogSource source,vector<tl_object_ptr<telegram_api::User>> users,vector<tl_object_ptr<telegram_api::Chat>> chats)38308 void MessagesManager::on_get_sponsored_dialog(tl_object_ptr<telegram_api::Peer> peer, DialogSource source,
38309                                               vector<tl_object_ptr<telegram_api::User>> users,
38310                                               vector<tl_object_ptr<telegram_api::Chat>> chats) {
38311   CHECK(peer != nullptr);
38312 
38313   td_->contacts_manager_->on_get_users(std::move(users), "on_get_sponsored_dialog");
38314   td_->contacts_manager_->on_get_chats(std::move(chats), "on_get_sponsored_dialog");
38315 
38316   set_sponsored_dialog(DialogId(peer), std::move(source));
38317 }
38318 
add_sponsored_dialog(const Dialog * d,DialogSource source)38319 void MessagesManager::add_sponsored_dialog(const Dialog *d, DialogSource source) {
38320   if (td_->auth_manager_->is_bot()) {
38321     return;
38322   }
38323 
38324   CHECK(!sponsored_dialog_id_.is_valid());
38325   sponsored_dialog_id_ = d->dialog_id;
38326   sponsored_dialog_source_ = std::move(source);
38327 
38328   // update last_pinned_dialog_date in any case, because all chats before SPONSORED_DIALOG_ORDER are known
38329   auto dialog_list_id = DialogListId(FolderId::main());
38330   auto *list = get_dialog_list(dialog_list_id);
38331   CHECK(list != nullptr);
38332   DialogDate max_dialog_date(SPONSORED_DIALOG_ORDER, d->dialog_id);
38333   if (list->last_pinned_dialog_date_ < max_dialog_date) {
38334     list->last_pinned_dialog_date_ = max_dialog_date;
38335     update_list_last_dialog_date(*list);
38336   }
38337 
38338   if (is_dialog_sponsored(d)) {
38339     send_update_chat_position(dialog_list_id, d, "add_sponsored_dialog");
38340     // the sponsored dialog must not be saved there
38341   }
38342 }
38343 
save_sponsored_dialog()38344 void MessagesManager::save_sponsored_dialog() {
38345   if (!G()->parameters().use_message_db) {
38346     return;
38347   }
38348 
38349   LOG(INFO) << "Save sponsored " << sponsored_dialog_id_ << " with source " << sponsored_dialog_source_;
38350   if (sponsored_dialog_id_.is_valid()) {
38351     G()->td_db()->get_binlog_pmc()->set(
38352         "sponsored_dialog_id",
38353         PSTRING() << sponsored_dialog_id_.get() << ' ' << sponsored_dialog_source_.DialogSource::serialize());
38354   } else {
38355     G()->td_db()->get_binlog_pmc()->erase("sponsored_dialog_id");
38356   }
38357 }
38358 
set_sponsored_dialog(DialogId dialog_id,DialogSource source)38359 void MessagesManager::set_sponsored_dialog(DialogId dialog_id, DialogSource source) {
38360   if (td_->auth_manager_->is_bot()) {
38361     return;
38362   }
38363   LOG(INFO) << "Change sponsored chat from " << sponsored_dialog_id_ << " to " << dialog_id;
38364   if (removed_sponsored_dialog_id_.is_valid() && dialog_id == removed_sponsored_dialog_id_) {
38365     return;
38366   }
38367 
38368   if (sponsored_dialog_id_ == dialog_id) {
38369     if (sponsored_dialog_source_ != source) {
38370       CHECK(sponsored_dialog_id_.is_valid());
38371       sponsored_dialog_source_ = std::move(source);
38372       const Dialog *d = get_dialog(sponsored_dialog_id_);
38373       CHECK(d != nullptr);
38374       send_update_chat_position(DialogListId(FolderId::main()), d, "set_sponsored_dialog");
38375       save_sponsored_dialog();
38376     }
38377     return;
38378   }
38379 
38380   bool need_update_total_chat_count = false;
38381   if (sponsored_dialog_id_.is_valid()) {
38382     const Dialog *d = get_dialog(sponsored_dialog_id_);
38383     CHECK(d != nullptr);
38384     bool was_sponsored = is_dialog_sponsored(d);
38385     sponsored_dialog_id_ = DialogId();
38386     sponsored_dialog_source_ = DialogSource();
38387     if (was_sponsored) {
38388       send_update_chat_position(DialogListId(FolderId::main()), d, "set_sponsored_dialog 2");
38389       need_update_total_chat_count = true;
38390     }
38391   }
38392 
38393   if (dialog_id.is_valid()) {
38394     force_create_dialog(dialog_id, "set_sponsored_dialog_id");
38395     const Dialog *d = get_dialog(dialog_id);
38396     CHECK(d != nullptr);
38397     add_sponsored_dialog(d, std::move(source));
38398     if (is_dialog_sponsored(d)) {
38399       need_update_total_chat_count = !need_update_total_chat_count;
38400     }
38401   }
38402 
38403   if (need_update_total_chat_count) {
38404     auto dialog_list_id = DialogListId(FolderId::main());
38405     auto *list = get_dialog_list(dialog_list_id);
38406     CHECK(list != nullptr);
38407     if (list->is_dialog_unread_count_inited_) {
38408       send_update_unread_chat_count(*list, DialogId(), true, "set_sponsored_dialog_id");
38409     }
38410   }
38411 
38412   save_sponsored_dialog();
38413 }
38414 
get_update_chat_filters_object() const38415 td_api::object_ptr<td_api::updateChatFilters> MessagesManager::get_update_chat_filters_object() const {
38416   CHECK(!td_->auth_manager_->is_bot());
38417   auto update = td_api::make_object<td_api::updateChatFilters>();
38418   for (const auto &filter : dialog_filters_) {
38419     update->chat_filters_.push_back(filter->get_chat_filter_info_object());
38420   }
38421   return update;
38422 }
38423 
get_update_unread_message_count_object(const DialogList & list) const38424 td_api::object_ptr<td_api::updateUnreadMessageCount> MessagesManager::get_update_unread_message_count_object(
38425     const DialogList &list) const {
38426   CHECK(!td_->auth_manager_->is_bot());
38427   CHECK(list.is_message_unread_count_inited_);
38428   int32 unread_count = list.unread_message_total_count_;
38429   int32 unread_unmuted_count = list.unread_message_total_count_ - list.unread_message_muted_count_;
38430   CHECK(unread_count >= 0);
38431   CHECK(unread_unmuted_count >= 0);
38432   return td_api::make_object<td_api::updateUnreadMessageCount>(list.dialog_list_id.get_chat_list_object(), unread_count,
38433                                                                unread_unmuted_count);
38434 }
38435 
get_update_unread_chat_count_object(const DialogList & list) const38436 td_api::object_ptr<td_api::updateUnreadChatCount> MessagesManager::get_update_unread_chat_count_object(
38437     const DialogList &list) const {
38438   CHECK(!td_->auth_manager_->is_bot());
38439   CHECK(list.is_dialog_unread_count_inited_);
38440   int32 unread_count = list.unread_dialog_total_count_;
38441   int32 unread_unmuted_count = unread_count - list.unread_dialog_muted_count_;
38442   int32 unread_marked_count = list.unread_dialog_marked_count_;
38443   int32 unread_unmuted_marked_count = unread_marked_count - list.unread_dialog_muted_marked_count_;
38444   CHECK(unread_count >= 0);
38445   CHECK(unread_unmuted_count >= 0);
38446   CHECK(unread_marked_count >= 0);
38447   CHECK(unread_unmuted_marked_count >= 0);
38448   return td_api::make_object<td_api::updateUnreadChatCount>(
38449       list.dialog_list_id.get_chat_list_object(), get_dialog_total_count(list), unread_count, unread_unmuted_count,
38450       unread_marked_count, unread_unmuted_marked_count);
38451 }
38452 
get_current_state(vector<td_api::object_ptr<td_api::Update>> & updates) const38453 void MessagesManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const {
38454   if (!td_->auth_manager_->is_bot()) {
38455     if (!dialog_filters_.empty()) {
38456       updates.push_back(get_update_chat_filters_object());
38457     }
38458     if (G()->parameters().use_message_db) {
38459       for (const auto &it : dialog_lists_) {
38460         auto &list = it.second;
38461         if (list.is_message_unread_count_inited_) {
38462           updates.push_back(get_update_unread_message_count_object(list));
38463         }
38464         if (list.is_dialog_unread_count_inited_) {
38465           updates.push_back(get_update_unread_chat_count_object(list));
38466         }
38467       }
38468     }
38469 
38470     vector<NotificationSettingsScope> scopes{NotificationSettingsScope::Private, NotificationSettingsScope::Group,
38471                                              NotificationSettingsScope::Channel};
38472     for (auto scope : scopes) {
38473       auto current_settings = get_scope_notification_settings(scope);
38474       CHECK(current_settings != nullptr);
38475       if (current_settings->is_synchronized) {
38476         updates.push_back(get_update_scope_notification_settings_object(scope));
38477       }
38478     }
38479   }
38480 
38481   vector<td_api::object_ptr<td_api::Update>> last_message_updates;
38482   for (auto &it : dialogs_) {
38483     const Dialog *d = it.second.get();
38484     auto update = td_api::make_object<td_api::updateNewChat>(get_chat_object(d));
38485     if (update->chat_->last_message_ != nullptr && update->chat_->last_message_->forward_info_ != nullptr) {
38486       last_message_updates.push_back(td_api::make_object<td_api::updateChatLastMessage>(
38487           d->dialog_id.get(), std::move(update->chat_->last_message_), get_chat_positions_object(d)));
38488     }
38489     updates.push_back(std::move(update));
38490 
38491     if (d->is_opened) {
38492       auto info_it = dialog_online_member_counts_.find(d->dialog_id);
38493       if (info_it != dialog_online_member_counts_.end() && info_it->second.is_update_sent) {
38494         updates.push_back(td_api::make_object<td_api::updateChatOnlineMemberCount>(
38495             d->dialog_id.get(), info_it->second.online_member_count));
38496       }
38497     }
38498   }
38499   append(updates, std::move(last_message_updates));
38500 }
38501 
38502 }  // namespace td
38503